Browse Source

refactoring to conform to PEP8 and picking up some suggestions from pylint

Helmut Pozimski 8 years ago
parent
commit
8e377343be

+ 1 - 0
Changelog

@@ -3,6 +3,7 @@
     changed the init script to create a separate directory for the PID file
     create the PID file in the separate directory and rename it to stdd.pid
     changed the main configuration file to json format
+    adjusted the whole codebase and style according to PEP8 and suggestions from pylint
 
 2014-07-12  Helmut Pozimski  <helmut@pozimski.eu>
 

+ 0 - 2
TODO

@@ -1,3 +1 @@
 * Add stdd.postrm?
-* Check code with pylint and improve it
-* Make code pep8 clean

+ 0 - 63
adafruit_7segment/Adafruit_7Segment.py

@@ -1,63 +0,0 @@
-# -*- coding: utf-8-*-
-#
-# This file is part of stdd, the simple time display daemon,
-# written by Helmut Pozimski <helmut@pozimski.eu>,
-# licensed under the 3-clause BSD license
-# This file was originally written by Written by Limor Fried, Kevin Townsend
-# and Mikey Sklar for Adafruit Industries. BSD license,
-# all text above must be included in any redistribution
-
-import time
-import datetime
-from Adafruit_LEDBackpack import LEDBackpack
-
-# ===========================================================================
-# 7-Segment Display
-# ===========================================================================
-
-# This class is meant to be used with the four-character, seven segment
-# displays available from Adafruit
-
-
-class SevenSegment:
-    disp = None
-
-  # Hexadecimal character lookup table (row 1 = 0..9, row 2 = A..F)
-    digits = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
-              0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71]
-
-  # Constructor
-    def __init__(self, address=0x70, debug=False):
-        if (debug):
-            print "Initializing a new instance of LEDBackpack at \
-            0x%02X" % address
-        self.disp = LEDBackpack(address=address, debug=debug)
-
-    def writeDigitRaw(self, charNumber, value):
-        "Sets a digit using the raw 16-bit value"
-        if (charNumber > 7):
-            return
-        # Set the appropriate digit
-        self.disp.setBufferRow(charNumber, value)
-
-    def writeDigit(self, charNumber, value, dot=False):
-        "Sets a single decimal or hexademical value (0..9 and A..F)"
-        if (charNumber > 7):
-            return
-        if (value > 0xF):
-            return
-        # Set the appropriate digit
-        self.disp.setBufferRow(charNumber, self.digits[value] | (dot << 7))
-
-    def setColon(self, state=True):
-        "Enables or disables the colon character"
-        # Warning: This function assumes that the colon is character '2',
-        # which is the case on 4 char displays, but may need to be modified
-        # if another display type is used
-        if (state):
-            self.disp.setBufferRow(2, 0xFFFF)
-        else:
-            self.disp.setBufferRow(2, 0)
-
-    def setBrightness(self, brightness):
-        self.disp.setBrightness(brightness)

+ 0 - 182
adafruit_7segment/Adafruit_I2C.py

@@ -1,182 +0,0 @@
-# -*- coding: utf-8-*-
-#
-# This file is part of stdd, the simple time display daemon,
-# written by Helmut Pozimski <helmut@pozimski.eu>,
-# licensed under the 3-clause BSD license
-# This file was originally written by Written by Limor Fried, Kevin Townsend
-# and Mikey Sklar for Adafruit Industries. BSD license,
-# all text above must be included in any redistribution
-
-import smbus
-
-# ===========================================================================
-# Adafruit_I2C Class
-# ===========================================================================
-
-
-class Adafruit_I2C:
-
-    @staticmethod
-    def getPiRevision():
-        "Gets the version number of the Raspberry Pi board"
-        # Courtesy quick2wire-python-api
-        # https://github.com/quick2wire/quick2wire-python-api
-        try:
-            with open('/proc/cpuinfo', 'r') as f:
-                for line in f:
-                    if line.startswith('Revision'):
-                        return 1 if line.rstrip()[-1] in ['1', '2'] else 2
-        except:
-            return 0
-
-    @staticmethod
-    def getPiI2CBusNumber():
-        # Gets the I2C bus number /dev/i2c#
-        return 1 if Adafruit_I2C.getPiRevision() > 1 else 0
-
-    def __init__(self, address, busnum=-1, debug=False):
-        self.address = address
-        # By default, the correct I2C bus is auto-detected using /proc/cpuinfo
-        # Alternatively, you can hard-code the bus version below:
-        # self.bus = smbus.SMBus(0); # Force I2C0 (early 256MB Pi's)
-        # self.bus = smbus.SMBus(1); # Force I2C1 (512MB Pi's)
-        self.bus = smbus.SMBus(
-            busnum if busnum >= 0 else Adafruit_I2C.getPiI2CBusNumber())
-        self.debug = debug
-
-    def reverseByteOrder(self, data):
-        "Reverses the byte order of an int (16-bit) or long (32-bit) value"
-        # Courtesy Vishal Sapre
-        byteCount = len(hex(data)[2:].replace('L', '')[::2])
-        val = 0
-        for i in range(byteCount):
-            val = (val << 8) | (data & 0xff)
-            data >>= 8
-        return val
-
-    def errMsg(self):
-        raise Exception("cannot connect to device, check hardware address!")
-        return -1
-
-    def write8(self, reg, value):
-        "Writes an 8-bit value to the specified register/address"
-        try:
-            self.bus.write_byte_data(self.address, reg, value)
-            if self.debug:
-                print "I2C: Wrote 0x%02X to register 0x%02X" % (value, reg)
-        except IOError, err:
-            return self.errMsg()
-
-    def write16(self, reg, value):
-        "Writes a 16-bit value to the specified register/address pair"
-        try:
-            self.bus.write_word_data(self.address, reg, value)
-            if self.debug:
-                print ("I2C: Wrote 0x%02X to register pair 0x%02X,0x%02X" %
-                      (value, reg, reg+1))
-        except IOError, err:
-            return self.errMsg()
-
-    def writeList(self, reg, list):
-        "Writes an array of bytes using I2C format"
-        try:
-            if self.debug:
-                print "I2C: Writing list to register 0x%02X:" % reg
-                print list
-            self.bus.write_i2c_block_data(self.address, reg, list)
-        except IOError, err:
-            return self.errMsg()
-
-    def readList(self, reg, length):
-        "Read a list of bytes from the I2C device"
-        try:
-            results = self.bus.read_i2c_block_data(self.address, reg, length)
-            if self.debug:
-                print ("I2C: Device 0x % 02X returned the following from \
-                       reg 0x % 02X" % (self.address, reg))
-                print results
-            return results
-        except IOError, err:
-            return self.errMsg()
-
-    def readU8(self, reg):
-        "Read an unsigned byte from the I2C device"
-        try:
-            result = self.bus.read_byte_data(self.address, reg)
-            if self.debug:
-                print ("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" %
-                      (self.address, result & 0xFF, reg))
-            return result
-        except IOError, err:
-            return self.errMsg()
-
-    def readS8(self, reg):
-        "Reads a signed byte from the I2C device"
-        try:
-            result = self.bus.read_byte_data(self.address, reg)
-            if result > 127: result -= 256
-            if self.debug:
-                print ("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" %
-                       (self.address, result & 0xFF, reg))
-            return result
-        except IOError, err:
-            return self.errMsg()
-
-    def readU16(self, reg):
-        "Reads an unsigned 16-bit value from the I2C device"
-        try:
-            hibyte = self.readU8(reg)
-            lobyte = self.readU8(reg+1)
-            result = (hibyte << 8) + lobyte
-            if (self.debug):
-                print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (
-                    self.address, result & 0xFFFF, reg)
-            return result
-        except IOError, err:
-            return self.errMsg()
-
-    def readS16(self, reg):
-        "Reads a signed 16-bit value from the I2C device"
-        try:
-            hibyte = self.readS8(reg)
-            lobyte = self.readU8(reg+1)
-            result = (hibyte << 8) + lobyte
-            if (self.debug):
-                print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (
-                    self.address, result & 0xFFFF, reg)
-            return result
-        except IOError, err:
-            return self.errMsg()
-
-    def readU16Rev(self, reg):
-        "Reads an unsigned 16-bit value from the I2C device with rev byte ord"
-        try:
-            lobyte = self.readU8(reg)
-            hibyte = self.readU8(reg+1)
-            result = (hibyte << 8) + lobyte
-            if (self.debug):
-                print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (
-                    self.address, result & 0xFFFF, reg)
-            return result
-        except IOError, err:
-            return self.errMsg()
-
-    def readS16Rev(self, reg):
-        "Reads a signed 16-bit value from the I2C device with rev byte order"
-        try:
-            lobyte = self.readS8(reg)
-            hibyte = self.readU8(reg+1)
-            result = (hibyte << 8) + lobyte
-            if (self.debug):
-                print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (
-                    self.address, result & 0xFFFF, reg)
-            return result
-        except IOError, err:
-            return self.errMsg()
-
-if __name__ == '__main__':
-    try:
-        bus = Adafruit_I2C(address=0)
-        print "Default I2C bus is accessible"
-    except:
-        print "Error accessing default I2C bus"

+ 0 - 95
adafruit_7segment/Adafruit_LEDBackpack.py

@@ -1,95 +0,0 @@
-# -*- coding: utf-8-*-
-#
-# This file is part of stdd, the simple time display daemon,
-# written by Helmut Pozimski <helmut@pozimski.eu>,
-# licensed under the 3-clause BSD license
-# This file was originally written by Written by Limor Fried, Kevin Townsend
-# and Mikey Sklar for Adafruit Industries. BSD license,
-# all text above must be included in any redistribution
-
-import time
-from copy import copy
-from Adafruit_I2C import Adafruit_I2C
-
-# ============================================================================
-# LEDBackpack Class
-# ============================================================================
-
-
-class LEDBackpack:
-    i2c = None
-
-    # Registers
-    __HT16K33_REGISTER_DISPLAY_SETUP = 0x80
-    __HT16K33_REGISTER_SYSTEM_SETUP = 0x20
-    __HT16K33_REGISTER_DIMMING = 0xE0
-
-    # Blink rate
-    __HT16K33_BLINKRATE_OFF = 0x00
-    __HT16K33_BLINKRATE_2HZ = 0x01
-    __HT16K33_BLINKRATE_1HZ = 0x02
-    __HT16K33_BLINKRATE_HALFHZ = 0x03
-
-    # Display buffer (8x16-bits)
-    __buffer = [0x0000, 0x0000, 0x0000, 0x0000,
-                0x0000, 0x0000, 0x0000, 0x0000]
-
-    # Constructor
-    def __init__(self, address=0x70, debug=False):
-        self.i2c = Adafruit_I2C(address)
-        self.address = address
-        self.debug = debug
-
-        # Turn the oscillator on
-        self.i2c.write8(self.__HT16K33_REGISTER_SYSTEM_SETUP | 0x01, 0x00)
-
-        # Turn blink off
-        self.setBlinkRate(self.__HT16K33_BLINKRATE_OFF)
-
-        # Set maximum brightness
-        self.setBrightness(15)
-
-        # Clear the screen
-        self.clear()
-
-    def setBrightness(self, brightness):
-        "Sets the brightness level from 0..15"
-        if (brightness > 15):
-            brightness = 15
-        self.i2c.write8(self.__HT16K33_REGISTER_DIMMING | brightness, 0x00)
-
-    def setBlinkRate(self, blinkRate):
-        "Sets the blink rate"
-        if (blinkRate > self.__HT16K33_BLINKRATE_HALFHZ):
-            blinkRate = self.__HT16K33_BLINKRATE_OFF
-        self.i2c.write8(self.__HT16K33_REGISTER_DISPLAY_SETUP | 0x01
-                        | (blinkRate << 1), 0x00)
-
-    def setBufferRow(self, row, value, update=True):
-        "Updates a single 16-bit entry in the 8*16-bit buffer"
-        if (row > 7):
-            return                    # Prevent buffer overflow
-        self.__buffer[row] = value  # value # & 0xFFFF
-        if (update):
-            self.writeDisplay()       # Update the display
-
-    def getBuffer(self):
-        "Returns a copy of the raw buffer contents"
-        bufferCopy = copy(self.__buffer)
-        return bufferCopy
-
-    def writeDisplay(self):
-        "Updates the display memory"
-        bytes = []
-        for item in self.__buffer:
-            bytes.append(item & 0xFF)
-            bytes.append((item >> 8) & 0xFF)
-        self.i2c.writeList(0x00, bytes)
-
-    def clear(self, update=True):
-        "Clears the display memory"
-        self.__buffer = [0, 0, 0, 0, 0, 0, 0, 0]
-        if (update):
-            self.writeDisplay()
-
-led = LEDBackpack(0x70)

+ 194 - 0
adafruit_7segment/i2c.py

@@ -0,0 +1,194 @@
+# -*- coding: utf-8-*-
+#
+# This file is part of stdd, the simple time display daemon,
+# written by Helmut Pozimski <helmut@pozimski.eu>,
+# licensed under the 3-clause BSD license
+# This file was originally written by Written by Limor Fried, Kevin Townsend
+# and Mikey Sklar for Adafruit Industries. BSD license,
+# all text above must be included in any redistribution
+
+"""
+===========================================================================
+AdafruitI2c Class
+===========================================================================
+"""
+
+from __future__ import print_function
+
+from smbus import SMBus
+
+
+class AdafruitI2c(object):
+    """ This class provides low level i2c access.
+    """
+    @staticmethod
+    def get_pi_revision():
+        """Gets the version number of the Raspberry Pi board"""
+        # Courtesy quick2wire-python-api
+        # https://github.com/quick2wire/quick2wire-python-api
+        try:
+            with open('/proc/cpuinfo', 'r') as file_obj:
+                for line in file_obj:
+                    if line.startswith('Revision'):
+                        return 1 if line.rstrip()[-1] in ['1', '2'] else 2
+        except IOError:
+            return 0
+
+    @staticmethod
+    def get_pi_i2c_bus_number():
+        """ Gets the I2C bus number /dev/i2c# """
+        return 1 if AdafruitI2c.get_pi_revision() > 1 else 0
+
+    def __init__(self, address, busnum=-1, debug=False):
+        self.address = address
+        # By default, the correct I2C bus is auto-detected using /proc/cpuinfo
+        # Alternatively, you can hard-code the bus version below:
+        # self.bus = smbus.SMBus(0); # Force I2C0 (early 256MB Pi's)
+        # self.bus = smbus.SMBus(1); # Force I2C1 (512MB Pi's)
+        self.bus = SMBus(
+            busnum if busnum >= 0 else AdafruitI2c.get_pi_i2c_bus_number())
+        self.debug = debug
+
+    @staticmethod
+    def reverse_byte_order(data):
+        """Reverses the byte order of an int (16-bit) or long (32-bit) value"""
+        # Courtesy Vishal Sapre
+        byte_count = len(hex(data)[2:].replace('L', '')[::2])
+        val = 0
+        for i in range(byte_count):
+            val = (val << 8) | (data & 0xff)
+            data >>= 8
+        return val
+
+    @staticmethod
+    def err_msg():
+        """Raises an exception."""
+        raise Exception("cannot connect to device, check hardware address!")
+
+    def write8(self, reg, value):
+        """Writes an 8-bit value to the specified register/address"""
+        try:
+            self.bus.write_byte_data(self.address, reg, value)
+            if self.debug:
+                print("I2C: Wrote 0x%02X to register 0x%02X" % (value, reg))
+        except IOError:
+            return self.err_msg()
+
+    def write16(self, reg, value):
+        """Writes a 16-bit value to the specified register/address pair"""
+        try:
+            self.bus.write_word_data(self.address, reg, value)
+            if self.debug:
+                print("I2C: Wrote 0x%02X to register pair 0x%02X,0x%02X" %
+                      (value, reg, reg+1))
+        except IOError:
+            return self.err_msg()
+
+    def write_list(self, reg, w_list):
+        """Writes an array of bytes using I2C format"""
+        try:
+            if self.debug:
+                print("I2C: Writing list to register 0x%02X:" % reg)
+                print(w_list)
+            self.bus.write_i2c_block_data(self.address, reg, w_list)
+        except IOError:
+            return self.err_msg()
+
+    def read_list(self, reg, length):
+        """Read a list of bytes from the I2C device"""
+        try:
+            results = self.bus.read_i2c_block_data(self.address, reg, length)
+            if self.debug:
+                print ("I2C: Device 0x % 02X returned the following from \
+                       reg 0x % 02X" % (self.address, reg))
+                print(results)
+            return results
+        except IOError:
+            return self.err_msg()
+
+    def read_u8(self, reg):
+        """Read an unsigned byte from the I2C device"""
+        try:
+            result = self.bus.read_byte_data(self.address, reg)
+            if self.debug:
+                print("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" %
+                      (self.address, result & 0xFF, reg))
+            return result
+        except IOError:
+            return self.err_msg()
+
+    def read_s8(self, reg):
+        """Reads a signed byte from the I2C device"""
+        try:
+            result = self.bus.read_byte_data(self.address, reg)
+            if result > 127:
+                result -= 256
+            if self.debug:
+                print("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" %
+                      (self.address, result & 0xFF, reg))
+            return result
+        except IOError:
+            return self.err_msg()
+
+    def read_u16(self, reg):
+        """Reads an unsigned 16-bit value from the I2C device"""
+        try:
+            hibyte = self.read_u8(reg)
+            lobyte = self.read_u8(reg+1)
+            result = (hibyte << 8) + lobyte
+            if self.debug:
+                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (
+                    self.address, result & 0xFFFF, reg))
+            return result
+        except IOError:
+            return self.err_msg()
+
+    def read_s16(self, reg):
+        """Reads a signed 16-bit value from the I2C device"""
+        try:
+            hibyte = self.read_s8(reg)
+            lobyte = self.read_u8(reg+1)
+            result = (hibyte << 8) + lobyte
+            if self.debug:
+                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" %
+                      (self.address, result & 0xFFFF, reg))
+            return result
+        except IOError:
+            return self.err_msg()
+
+    def read_u16_rev(self, reg):
+        """Reads an unsigned 16-bit value from the I2C device with rev byte
+        order.
+        """
+        try:
+            lobyte = self.read_u8(reg)
+            hibyte = self.read_u8(reg+1)
+            result = (hibyte << 8) + lobyte
+            if self.debug:
+                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" %
+                      (self.address, result & 0xFFFF, reg))
+            return result
+        except IOError:
+            return self.err_msg()
+
+    def read_s16_rev(self, reg):
+        """Reads a signed 16-bit value from the I2C device with rev byte
+        order.
+        """
+        try:
+            lobyte = self.read_s8(reg)
+            hibyte = self.read_u8(reg+1)
+            result = (hibyte << 8) + lobyte
+            if self.debug:
+                print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (
+                    self.address, result & 0xFFFF, reg))
+            return result
+        except IOError:
+            return self.err_msg()
+
+if __name__ == '__main__':
+    try:
+        BUS = AdafruitI2c(address=0)
+        print("Default I2C bus is accessible")
+    except:
+        print("Error accessing default I2C bus")

+ 97 - 0
adafruit_7segment/ledbackpack.py

@@ -0,0 +1,97 @@
+# -*- coding: utf-8-*-
+#
+# This file is part of stdd, the simple time display daemon,
+# written by Helmut Pozimski <helmut@pozimski.eu>,
+# licensed under the 3-clause BSD license
+# This file was originally written by Written by Limor Fried, Kevin Townsend
+# and Mikey Sklar for Adafruit Industries. BSD license,
+# all text above must be included in any redistribution
+
+"""
+============================================================================
+LEDBackpack Class
+============================================================================
+"""
+
+from copy import copy
+from adafruit_7segment.i2c import AdafruitI2c
+
+
+class LEDBackpack(object):
+    """Represents the LED backpack and allows access to it. """
+    i2c = None
+
+    # Registers
+    __HT16K33_REGISTER_DISPLAY_SET = 0x80
+    __HT16K33_REGISTER_SYSTEM_SETUP = 0x20
+    __HT16K33_REGISTER_DIMMING = 0xE0
+
+    # Blink rate
+    __HT16K33_BLINKRATE_OFF = 0x00
+    __HT16K33_BLINKRATE_2HZ = 0x01
+    __HT16K33_BLINKRATE_1HZ = 0x02
+    __HT16K33_BLINKRATE_HALFHZ = 0x03
+
+    # Display buffer (8x16-bits)
+    __buffer = [0x0000, 0x0000, 0x0000, 0x0000,
+                0x0000, 0x0000, 0x0000, 0x0000]
+
+    # Constructor
+    def __init__(self, address=0x70, debug=False):
+        self.i2c = AdafruitI2c(address)
+        self.address = address
+        self.debug = debug
+
+        # Turn the oscillator on
+        self.i2c.write8(self.__HT16K33_REGISTER_SYSTEM_SETUP | 0x01, 0x00)
+
+        # Turn blink off
+        self.set_blink_rate(self.__HT16K33_BLINKRATE_OFF)
+
+        # Set maximum brightness
+        self.set_brightness(15)
+
+        # Clear the screen
+        self.clear()
+
+    def set_brightness(self, brightness):
+        """Sets the brightness level from 0..15"""
+        if brightness > 15:
+            brightness = 15
+        self.i2c.write8(self.__HT16K33_REGISTER_DIMMING | brightness, 0x00)
+
+    def set_blink_rate(self, blink_rate):
+        """Sets the blink rate"""
+        if blink_rate > self.__HT16K33_BLINKRATE_HALFHZ:
+            blink_rate = self.__HT16K33_BLINKRATE_OFF
+        self.i2c.write8(self.__HT16K33_REGISTER_DISPLAY_SET | 0x01
+                        | (blink_rate << 1), 0x00)
+
+    def set_buffer_row(self, row, value, update=True):
+        """Updates a single 16-bit entry in the 8*16-bit buffer"""
+        if row > 7:
+            return                    # Prevent buffer overflow
+        self.__buffer[row] = value  # value # & 0xFFFF
+        if update:
+            self.write_display()       # Update the display
+
+    def get_buffer(self):
+        """Returns a copy of the raw buffer contents"""
+        buffer_copy = copy(self.__buffer)
+        return buffer_copy
+
+    def write_display(self):
+        """Updates the display memory"""
+        byte_list = []
+        for item in self.__buffer:
+            byte_list.append(item & 0xFF)
+            byte_list.append((item >> 8) & 0xFF)
+        self.i2c.write_list(0x00, byte_list)
+
+    def clear(self, update=True):
+        """Clears the display memory"""
+        self.__buffer = [0, 0, 0, 0, 0, 0, 0, 0]
+        if update:
+            self.write_display()
+
+LED = LEDBackpack(0x70)

+ 69 - 0
adafruit_7segment/sevensegment.py

@@ -0,0 +1,69 @@
+# -*- coding: utf-8-*-
+#
+# This file is part of stdd, the simple time display daemon,
+# written by Helmut Pozimski <helmut@pozimski.eu>,
+# licensed under the 3-clause BSD license
+# This file was originally written by Written by Limor Fried, Kevin Townsend
+# and Mikey Sklar for Adafruit Industries. BSD license,
+# all text above must be included in any redistribution
+
+"""
+===========================================================================
+ 7-Segment Display
+===========================================================================
+
+ This class is meant to be used with the four-character, seven segment
+ displays available from Adafruit.
+"""
+
+
+from __future__ import print_function
+from adafruit_7segment.ledbackpack import LEDBackpack
+
+
+class SevenSegment(object):
+    """This class represents the seven segment display and allows to access and
+    write data to it.
+    """
+    disp = None
+
+    # Hexadecimal character lookup table (row 1 = 0..9, row 2 = A..F)
+    digits = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
+              0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71]
+
+    # Constructor
+    def __init__(self, address=0x70, debug=False):
+        if debug:
+            print("Initializing a new instance of LEDBackpack at \
+            0x%02X" % address)
+        self.disp = LEDBackpack(address=address, debug=debug)
+
+    def write_digit_raw(self, char_number, value):
+        """Sets a digit using the raw 16-bit value"""
+        if char_number > 7:
+            return
+        # Set the appropriate digit
+        self.disp.set_buffer_row(char_number, value)
+
+    def write_digit(self, char_number, value, dot=False):
+        """Sets a single decimal or hexademical value (0..9 and A..F)"""
+        if char_number > 7:
+            return
+        if value > 0xF:
+            return
+        # Set the appropriate digit
+        self.disp.set_buffer_row(char_number, self.digits[value] | (dot << 7))
+
+    def set_colon(self, state=True):
+        """Enables or disables the colon character"""
+        # Warning: This function assumes that the colon is character '2',
+        # which is the case on 4 char displays, but may need to be modified
+        # if another display type is used
+        if state:
+            self.disp.set_buffer_row(2, 0xFFFF)
+        else:
+            self.disp.set_buffer_row(2, 0)
+
+    def set_brightness(self, brightness):
+        """ Sets the brightness. """
+        self.disp.set_brightness(brightness)

+ 6 - 0
debian/changelog

@@ -1,3 +1,9 @@
+stdd (0.9.5-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Helmut Pozimski <helmut@pozimski.eu>  Sun, 02 Aug 2015 14:18:00 +0200
+
 stdd (0.9.4-1) unstable; urgency=low
 
   * New upstream release

+ 2 - 2
doc/stdd.1

@@ -1,4 +1,4 @@
-.TH STDD 1 "28 July, 2013" 0.9.2 stdd
+.TH STDD 1 "28 July, 2013" 0.9.5 stdd
 .SH NAME
 stdd \- a daemon to display the current time on a 7 segment display
 .SH SYNOPSIS
@@ -74,7 +74,7 @@ sample code used in this project
 .SH AUTHOR
 Helmut Pozimski
 .SH COPYRIGHT
-2013,  Helmut  Pozimski, 3-Clause BSD license
+2013-2015,  Helmut  Pozimski, 3-Clause BSD license
 .P
 some parts written by Limor Fried, Kevin Townsend and Mikey Sklar for Adafruit Industries
 .P

+ 8 - 4
setup.py

@@ -6,18 +6,22 @@
 
 # -*- coding: utf8 -*-
 
+
+""" setup.py for stdd using distutils. """
 from distutils.core import setup
 
 setup(
     name="stdd",
-    version="0.9.4",
+    version="0.9.5",
     author_email="helmut@pozimski.eu",
     description="stdd, simple time display daemon",
     long_description=("stdd is a small daemon written in python which displays"
-            "the current time on a 7 segment display from Adafruit attached "
-            "via i2c"),
+                      " the current time on a 7 segment display from Adafruit "
+                      "attached via i2c"),
     license="3-clause BSD license",
     packages=["adafruit_7segment", "stddlib"],
     scripts=["stdd"],
-    data_files=[('/etc', ['config/stdd.json']), ('/etc/default', ['default/stdd'])  ]
+    data_files=[('/etc', ['config/stdd.json']),
+                ('/etc/default', ['default/stdd'])],
+    requires=['prctl']
 )

+ 96 - 104
stdd

@@ -5,6 +5,10 @@
 # written by Helmut Pozimski <helmut@pozimski.eu> 2013-2014,
 # licensed under the 3-clause BSD license
 
+""" Main script for stdd, puts all the modules together, starts the daemon and
+takes care of sending the right values to the display.
+"""
+
 import datetime
 import time
 import sys
@@ -16,158 +20,146 @@ from optparse import OptionParser
 
 import stddlib.daemon
 import stddlib.configuration
-from adafruit_7segment.Adafruit_7Segment import SevenSegment
-
-
-"""Create the OptionParser object, define and parse all options and
-parameters, only 3 are currently defined:
+from adafruit_7segment.sevensegment import SevenSegment
 
-    * --daemon (shall stdd be run as daemon)
-    * --user (user to change to)
-    * --group (group to change to)
-    * --config (path to configuration file)
 
-"""
-parser = OptionParser(prog="stdd", version="%prog 0.9.2", add_help_option=True)
-parser.add_option("-d", "--daemon", action="store_true", dest="daemon",
+PARSER = OptionParser(prog="stdd", version="%prog 0.9.2", add_help_option=True)
+PARSER.add_option("-d", "--daemon", action="store_true", dest="daemon",
                   help="run stdd as daemon")
-parser.add_option("-u", "--user", dest="user", help="define an unprivileged \
+PARSER.add_option("-u", "--user", dest="user", help="define an unprivileged \
     user to run the daemon")
-parser.add_option("-g", "--group", dest="group", help="define an unprivileged\
+PARSER.add_option("-g", "--group", dest="group", help="define an unprivileged\
     group to run the daemon")
-parser.add_option("-c", "--config", dest="config", help="define an\
+PARSER.add_option("-c", "--config", dest="config", help="define an\
     alternative path to the configuration file")
-(options, arguments) = parser.parse_args()
+(OPTIONS, ARGUMENTS) = PARSER.parse_args()
 
 """ define a sighandler to properly catch signals """
 
 
 def sighandler(signum, frame):
+    """ Catches signals and ensures a clean exit. """
     if signum == 2:
-        logger.info("received SIGINT, stopping daemon")
+        LOGGER.info("received SIGINT, stopping daemon")
     elif signum == 15:
-        logger.info("received SIGTERM, stopping daemon")
-    display.writeDigit(0, 0)
-    display.writeDigit(1, 0)
-    display.writeDigit(3, 0)
-    display.writeDigit(4, 0)
-    if options.daemon is True:
-        if daemon.Stop() is True:
+        LOGGER.info("received SIGTERM, stopping daemon")
+    DISPLAY.write_digit(0, 0)
+    DISPLAY.write_digit(1, 0)
+    DISPLAY.write_digit(3, 0)
+    DISPLAY.write_digit(4, 0)
+    if OPTIONS.daemon is True:
+        if DAEMON.stop() is True:
             sys.exit(0)
         else:
-            logger.error("stopping daemon failed, PID file was not deleted!")
+            LOGGER.error("stopping daemon failed, PID file was not deleted!")
             sys.exit(1)
     sys.exit(0)
 
-""" create the configuration object according to the given parameters and
-read the file itself
-
-"""
+# create the configuration object according to the given parameters and
+# read the file itself
 
 signal.signal(signal.SIGTERM, sighandler)
 signal.signal(signal.SIGINT, sighandler)
 
-config = stddlib.configuration.Conf()
-if options.config is not None:
-    config.Read(options.config)
+CONFIG = stddlib.configuration.Conf()
+if OPTIONS.config is not None:
+    CONFIG.read(OPTIONS.config)
 else:
-    config.Read()
-config.Analyze()
+    CONFIG.read()
+CONFIG.analyze()
 
 
-""" create a logger to log errors according to configuration """
+# create a logger to log errors according to configuration
 
-logger = logging.getLogger("stdd")
+LOGGER = logging.getLogger("stdd")
 
-if config.syslog_level == "debug":
-    logger.setLevel(logging.DEBUG)
-elif config.syslog_level == "error":
-    logger.setLevel(logging.ERROR)
+if CONFIG.syslog_level == "debug":
+    LOGGER.setLevel(logging.DEBUG)
+elif CONFIG.syslog_level == "error":
+    LOGGER.setLevel(logging.ERROR)
 else:
-    logger.setLevel(logging.INFO)
+    LOGGER.setLevel(logging.INFO)
 
-if config.syslog_facility == "daemon":
-    syslog_handler = logging.handlers.SysLogHandler(
+if CONFIG.syslog_facility == "daemon":
+    SYSLOG_HANDLER = logging.handlers.SysLogHandler(
         "/dev/log",
         facility=logging.handlers.SysLogHandler.LOG_DAEMON)
 else:
-    syslog_handler = logging.handlers.SysLogHandler("/dev/log")
+    SYSLOG_HANDLER = logging.handlers.SysLogHandler("/dev/log")
 
-console_handler = logging.StreamHandler()
+CONSOLE_HANDLER = logging.StreamHandler()
 
-formatter = logging.Formatter("%(name)s[" + str(os.getpid()) +
+FORMATTER = logging.Formatter("%(name)s[" + str(os.getpid()) +
                               "]: %(message)s")
 
-syslog_handler.setFormatter(formatter)
-console_handler.setFormatter(formatter)
+SYSLOG_HANDLER.setFormatter(FORMATTER)
+CONSOLE_HANDLER.setFormatter(FORMATTER)
 
-if options.daemon is True:
-    logger.addHandler(syslog_handler)
+if OPTIONS.daemon is True:
+    LOGGER.addHandler(SYSLOG_HANDLER)
 else:
-    logger.addHandler(console_handler)
+    LOGGER.addHandler(CONSOLE_HANDLER)
 
-if options.daemon is True:
+if OPTIONS.daemon is True:
     if os.access("/run", os.F_OK & os.W_OK) is True:
-        daemon = stddlib.daemon.Daemon("/run/stdd", "stdd.pid")
+        DAEMON = stddlib.daemon.Daemon("/run/stdd", "stdd.pid")
     else:
-        daemon = stddlib.daemon.Daemon("/var/run/stdd", "stdd.pid")
-    daemon.Daemonize()
-    daemon.Start()
-    logger.info("daemon started")
-    cmdline = ""
-    cmdcounter = 0
+        DAEMON = stddlib.daemon.Daemon("/var/run/stdd", "stdd.pid")
+    DAEMON.daemonize()
+    DAEMON.start()
+    LOGGER.info("daemon started")
+    CMDLINE = ""
+    CMDCOUNTER = 0
     for element in sys.argv:
-        if cmdcounter > 0:
-            cmdline = cmdline + " " + element
+        if CMDCOUNTER > 0:
+            CMDLINE = CMDLINE + " " + element
         else:
-            cmdline = cmdline + element
-        cmdcounter += 1
-    daemon.SetName("stdd", cmdline)
-    if options.user is not None and options.group is not None:
-        daemon.DropPriv(options.user, options.group)
-        logger.debug("dropped privileges, now running as " + options.user +
-                     " and group" + options.group)
-
-"""Initialize the display object"""
-display = SevenSegment(config.hw_address)
-logger.debug("opened hardware address")
-
-"""Set the brightness according to the configuration"""
-if datetime.datetime.now().time() > config.set_brightness_high and \
-        datetime.datetime.now().time() < config.set_brightness_low:
-    logger.debug("setting display brightness high")
-    display.setBrightness(config.brightness_high)
+            CMDLINE = CMDLINE + element
+        CMDCOUNTER += 1
+    DAEMON.set_name("stdd", CMDLINE)
+    if OPTIONS.user is not None and OPTIONS.group is not None:
+        DAEMON.drop_privileges(OPTIONS.user, OPTIONS.group)
+        LOGGER.debug("dropped privileges, now running as " + OPTIONS.user +
+                     " and group" + OPTIONS.group)
+
+# Initialize the display object
+DISPLAY = SevenSegment(CONFIG.hw_address)
+LOGGER.debug("opened hardware address")
+
+# Set the brightness according to the configuration
+if CONFIG.set_brightness_high < datetime.datetime.now().time()\
+        < CONFIG.set_brightness_low:
+    LOGGER.debug("setting display brightness high")
+    DISPLAY.set_brightness(CONFIG.brightness_high)
 else:
-    logger.debug("setting display brightness low")
-    display.setBrightness(config.brightness_low)
-
-"""Define the main loop"""
+    LOGGER.debug("setting display brightness low")
+    DISPLAY.set_brightness(CONFIG.brightness_low)
 
+# Define the main loop
 
 def main():
+    """ Main loop of the daemon.  """
     minute_written = 61
     while True:
         date_now = datetime.datetime.now()
-        logger.debug("got datetime: " + str(date_now))
+        LOGGER.debug("got datetime: " + str(date_now))
         minute = date_now.minute
         hour = date_now.hour
-        if config.blink_colon is True:
-            logger.debug("blinking middle colon")
-            display.setColon(date_now.second % 2)
+        if CONFIG.blink_colon is True:
+            LOGGER.debug("blinking middle colon")
+            DISPLAY.set_colon(date_now.second % 2)
         else:
-            display.setColon(True)
-        """set the display brightness high or low when the point in time
-        defined is reached.
-
-        """
-        if config.set_brightness_low.hour == hour:
-            if config.set_brightness_low.minute == minute:
-                logger.debug("setting display brightness low")
-                display.setBrightness(config.brightness_low)
-        if config.set_brightness_high.hour == hour:
-            if config.set_brightness_high.minute == minute:
-                logger.debug("setting display brightness high")
-                display.setBrightness(config.brightness_high)
+            DISPLAY.set_colon(True)
+        # set the display brightness high or low when the point in time
+        # defined is reached.
+        if CONFIG.set_brightness_low.hour == hour:
+            if CONFIG.set_brightness_low.minute == minute:
+                LOGGER.debug("setting display brightness low")
+                DISPLAY.set_brightness(CONFIG.brightness_low)
+        if CONFIG.set_brightness_high.hour == hour:
+            if CONFIG.set_brightness_high.minute == minute:
+                LOGGER.debug("setting display brightness high")
+                DISPLAY.set_brightness(CONFIG.brightness_high)
         if minute_written != minute:
             try:
                 position2 = str(hour)[1]
@@ -184,11 +176,11 @@ def main():
                 position3 = "0"
             else:
                 position3 = str(minute)[0]
-            logger.debug("writing time to display")
-            display.writeDigit(0, int(position1))
-            display.writeDigit(1, int(position2))
-            display.writeDigit(3, int(position3))
-            display.writeDigit(4, int(position4))
+            LOGGER.debug("writing time to display")
+            DISPLAY.write_digit(0, int(position1))
+            DISPLAY.write_digit(1, int(position2))
+            DISPLAY.write_digit(3, int(position3))
+            DISPLAY.write_digit(4, int(position4))
             minute_written = minute
         time.sleep(1)
 

+ 28 - 20
stddlib/configuration.py

@@ -4,16 +4,24 @@
 # written by Helmut Pozimski <helmut@pozimski.eu>,
 # licensed under the 3-clause BSD license
 
+""" This module reads the configuration from the main configuration file and
+ exposes it to other modules for further processing.
+ """
+
 import datetime
 import json
 
+
 class Conf(object):
+    """ Represents the configuration and allows accessing it's valued through
+    public attributes.
+    """
     def __init__(self):
         """creates the object prepopulated with some reasonable default
         values
 
         """
-        self.__values = {
+        self._values = {
             "hw_address": "",
             "blink_colon": "0",
             "brightness_high": "15",
@@ -34,31 +42,31 @@ class Conf(object):
         self.syslog_level = ""
         self.syslog_facility = ""
 
-    def Read(self, file_path="/etc/stdd.json"):
+    def read(self, file_path="/etc/stdd.json"):
         """reads the configuration file from the path given to the function,
         default to /etc/stdd.conf if empty"""
-        self.__conffile = open(file_path, "r")
-        config_read = json.load(self.__conffile)
+        conffile = open(file_path, "r")
+        config_read = json.load(conffile)
         for value in config_read:
             if value:
-                self.__values[value] = config_read[value]
-        self.__conffile.close()
+                self._values[value] = config_read[value]
+        conffile.close()
 
-    def Analyze(self):
+    def analyze(self):
         """takes the values from the list, converts them to the needed data
         types and writes them into the prepared attributes
 
         """
-        self.hw_address = int(self.__values["hw_address"], 16)
-        self.blink_colon = self.__values["blink_colon"]
-        self.brightness_high = self.__values["brightness_high"]
-        self.brightness_low = self.__values["brightness_low"]
-        self.__timetemp = self.__values["set_brightness_high"].split(":")
-        self.set_brightness_high = datetime.time(int(self.__timetemp[0]),
-                                                 int(self.__timetemp[1]))
-        self.__timetemp = self.__values["set_brightness_low"].split(":")
-        self.set_brightness_low = datetime.time(int(self.__timetemp[0]),
-                                                int(self.__timetemp[1]))
-        self.syslog_level = self.__values["syslog_level"]
-        self.syslog_facility = self.__values["syslog_facility"]
-        del self.__values
+        self.hw_address = int(self._values["hw_address"], 16)
+        self.blink_colon = self._values["blink_colon"]
+        self.brightness_high = self._values["brightness_high"]
+        self.brightness_low = self._values["brightness_low"]
+        timetemp = self._values["set_brightness_high"].split(":")
+        self.set_brightness_high = datetime.time(int(timetemp[0]),
+                                                 int(timetemp[1]))
+        timetemp = self._values["set_brightness_low"].split(":")
+        self.set_brightness_low = datetime.time(int(timetemp[0]),
+                                                int(timetemp[1]))
+        self.syslog_level = self._values["syslog_level"]
+        self.syslog_facility = self._values["syslog_facility"]
+        del self._values

+ 30 - 24
stddlib/daemon.py

@@ -4,6 +4,12 @@
 # written by Helmut Pozimski <helmut@pozimski.eu>,
 # licensed under the 3-clause BSD license
 
+""" Generic module to implement a daemon in python, takes care of the creation
+of the PID files and the usual daemonizing stuff.
+"""
+
+from __future__ import unicode_literals
+
 import os
 import sys
 
@@ -16,30 +22,30 @@ class Daemon(object):
 
     def __init__(self, pfile_path, pfile_name):
         """ Initializes the object. """
-        self.__pfile_path = pfile_path
-        self.__pfile_name = pfile_name
-        self.__daemon = False
+        self._pfile_path = pfile_path
+        self._pfile_name = pfile_name
+        self._daemon = False
 
-    def Daemonize(self):
+    def daemonize(self):
         """ Turns the calling prozess into a daemon running on it's own """
 
         try:
             # Fork for the first time
-            self.__pid = os.fork()
+            pid = os.fork()
         except OSError:
             sys.exit(os.EX_OSERR)
         else:
-            if self.__pid > 0:
+            if pid > 0:
                 sys.exit(os.EX_OK)
         # Become session and group leader
         os.setsid()
         try:
-            #Fork for the second time
-            self.__pid = os.fork()
+            # Fork for the second time
+            pid = os.fork()
         except OSError:
             sys.exit(os.EX_OSERR)
         else:
-            if self.__pid > 0:
+            if pid > 0:
                 sys.exit(os.EX_OK)
         # Change cwd to / to avoid interfering with other mounted file systems
         os.chdir("/")
@@ -56,12 +62,12 @@ class Daemon(object):
         os.open("/dev/null", 1)
         os.open("/dev/null", 2)
 
-        self.__daemon = True
+        self._daemon = True
 
-    def DropPriv(self, user, group):
+    def drop_privileges(self, user, group):
         """ If the daemon is running as root user, drop privileges and continue
         running as the defined unprivileged user. """
-        pid_file_path = os.path.join(self.__pfile_path, self.__pfile_name)
+        pid_file_path = os.path.join(self._pfile_path, self._pfile_name)
         passwd_file = open("/etc/passwd", "r")
         group_file = open("/etc/group", "r")
         uid = ""
@@ -81,7 +87,8 @@ class Daemon(object):
             os.setgid(int(gid))
             os.setuid(int(uid))
 
-    def SetName(self, name, cmdline):
+    @staticmethod
+    def set_name(name, cmdline):
         """ Sets the name of the process shown visible in ps and top,
         this allows to make your daemon look more like a standalone
         program instead of a python script.
@@ -98,26 +105,25 @@ class Daemon(object):
             prctl.set_proctitle(cmdline)
             return True
 
-    def Start(self):
+    def start(self):
         """ Performs the operations needed to "start" the daemon """
-        if self.__daemon is True:
-            if os.access(self.__pfile_path, os.F_OK & os.W_OK):
-                self.__pidfile = open(os.path.join(self.__pfile_path,
-                                                   self.__pfile_name),
-                                      "w")
-                self.__pidfile.write(unicode(os.getpid()) + "\n")
-                self.__pidfile.close()
+        if self._daemon is True:
+            if os.access(self._pfile_path, os.F_OK & os.W_OK):
+                pidfile = open(os.path.join(self._pfile_path,
+                                            self._pfile_name), "w")
+                pidfile.write(str(os.getpid()) + "\n")
+                pidfile.close()
                 return True
             else:
                 return False
         else:
             return False
 
-    def Stop(self):
+    def stop(self):
         """ Performs the operations needed to stop the daemon """
-        if self.__daemon is True:
+        if self._daemon is True:
             try:
-                os.remove(os.path.join(self.__pfile_path, self.__pfile_name))
+                os.remove(os.path.join(self._pfile_path, self._pfile_name))
             except OSError:
                 return False
             else: