diff --git a/lcd_manager.py b/lcd_manager.py new file mode 100644 index 0000000..6def000 --- /dev/null +++ b/lcd_manager.py @@ -0,0 +1,234 @@ +from time import sleep + +class Adafruit_CharLCD: + + # commands + LCD_CLEARDISPLAY = 0x01 + LCD_RETURNHOME = 0x02 + LCD_ENTRYMODESET = 0x04 + LCD_DISPLAYCONTROL = 0x08 + LCD_CURSORSHIFT = 0x10 + LCD_FUNCTIONSET = 0x20 + LCD_SETCGRAMADDR = 0x40 + LCD_SETDDRAMADDR = 0x80 + + # flags for display entry mode + LCD_ENTRYRIGHT = 0x00 + LCD_ENTRYLEFT = 0x02 + LCD_ENTRYSHIFTINCREMENT = 0x01 + LCD_ENTRYSHIFTDECREMENT = 0x00 + + # flags for display on/off control + LCD_DISPLAYON = 0x04 + LCD_DISPLAYOFF = 0x00 + LCD_CURSORON = 0x02 + LCD_CURSOROFF = 0x00 + LCD_BLINKON = 0x01 + LCD_BLINKOFF = 0x00 + + # flags for display/cursor shift + LCD_DISPLAYMOVE = 0x08 + LCD_CURSORMOVE = 0x00 + + # flags for display/cursor shift + LCD_DISPLAYMOVE = 0x08 + LCD_CURSORMOVE = 0x00 + LCD_MOVERIGHT = 0x04 + LCD_MOVELEFT = 0x00 + + # flags for function set + LCD_8BITMODE = 0x10 + LCD_4BITMODE = 0x00 + LCD_2LINE = 0x08 + LCD_1LINE = 0x00 + LCD_5x10DOTS = 0x04 + LCD_5x8DOTS = 0x00 + + def __init__(self, pin_rs=24, pin_e=23, pin_b=4, pins_db=[17, 25, 27, 22], GPIO=None): + # Emulate the old behavior of using RPi.GPIO if we haven't been given + # an explicit GPIO interface to use + if not GPIO: + import RPi.GPIO as GPIO + self.GPIO = GPIO + self.pin_rs = pin_rs + self.pin_e = pin_e + self.pin_b = pin_b + self.pins_db = pins_db + + self.GPIO.setwarnings(False) + self.GPIO.setmode(GPIO.BCM) + self.GPIO.setup(self.pin_e, GPIO.OUT) + self.GPIO.setup(self.pin_rs, GPIO.OUT) + self.GPIO.setup(self.pin_b, GPIO.OUT) + + for pin in self.pins_db: + self.GPIO.setup(pin, GPIO.OUT) + + self.GPIO.output(self.pin_b, True) + + self.write4bits(0x33) # initialization + self.write4bits(0x32) # initialization + self.write4bits(0x28) # 2 line 5x7 matrix + self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor + self.write4bits(0x06) # shift cursor right + + self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF + + self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS + self.displayfunction |= self.LCD_2LINE + + """ Initialize to default text direction (for romance languages) """ + self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT + self.write4bits(self.LCD_ENTRYMODESET | + self.displaymode) # set the entry mode + + self.clear() + + def begin(self, cols, lines): + + if (lines > 1): + self.numlines = lines + self.displayfunction |= self.LCD_2LINE + self.currline = 0 + + def home(self): + + self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero + self.delayMicroseconds(3000) # this command takes a long time! + + def clear(self): + + self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display + # 3000 microsecond sleep, clearing the display takes a long time + self.delayMicroseconds(3000) + + def setCursor(self, col, row): + + self.row_offsets = [0x00, 0x40, 0x14, 0x54] + + if (row > self.numlines): + row = self.numlines - 1 # we count rows starting w/0 + + self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row])) + + def noDisplay(self): + """ Turn the display off (quickly) """ + self.GPIO.output(self.pin_b, False) + self.displaycontrol &= ~self.LCD_DISPLAYON + self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) + + def display(self): + """ Turn the display on (quickly) """ + self.GPIO.output(self.pin_b, True) + self.displaycontrol |= self.LCD_DISPLAYON + self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) + + def noCursor(self): + """ Turns the underline cursor on/off """ + + self.displaycontrol &= ~self.LCD_CURSORON + self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) + + def cursor(self): + """ Cursor On """ + + self.displaycontrol |= self.LCD_CURSORON + self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) + + def noBlink(self): + """ Turn on and off the blinking cursor """ + + self.displaycontrol &= ~self.LCD_BLINKON + self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) + + def noBlink(self): + """ Turn on and off the blinking cursor """ + + self.displaycontrol &= ~self.LCD_BLINKON + self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) + + def DisplayLeft(self): + """ These commands scroll the display without changing the RAM """ + + self.write4bits(self.LCD_CURSORSHIFT | + self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT) + + def scrollDisplayRight(self): + """ These commands scroll the display without changing the RAM """ + + self.write4bits(self.LCD_CURSORSHIFT | + self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT) + + def leftToRight(self): + """ This is for text that flows Left to Right """ + + self.displaymode |= self.LCD_ENTRYLEFT + self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) + + def rightToLeft(self): + """ This is for text that flows Right to Left """ + self.displaymode &= ~self.LCD_ENTRYLEFT + self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) + + def autoscroll(self): + """ This will 'right justify' text from the cursor """ + + self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT + self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) + + def noAutoscroll(self): + """ This will 'left justify' text from the cursor """ + + self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT + self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) + + def write4bits(self, bits, char_mode=False): + """ Send command to LCD """ + + self.delayMicroseconds(1000) # 1000 microsecond sleep + + bits = bin(bits)[2:].zfill(8) + + self.GPIO.output(self.pin_rs, char_mode) + + for pin in self.pins_db: + self.GPIO.output(pin, False) + + for i in range(4): + if bits[i] == "1": + self.GPIO.output(self.pins_db[::-1][i], True) + + self.pulseEnable() + + for pin in self.pins_db: + self.GPIO.output(pin, False) + + for i in range(4, 8): + if bits[i] == "1": + self.GPIO.output(self.pins_db[::-1][i-4], True) + + self.pulseEnable() + + def delayMicroseconds(self, microseconds): + # divide microseconds by 1 million for seconds + seconds = microseconds / float(1000000) + sleep(seconds) + + def pulseEnable(self): + self.GPIO.output(self.pin_e, False) + # 1 microsecond pause - enable pulse must be > 450ns + self.delayMicroseconds(1) + self.GPIO.output(self.pin_e, True) + # 1 microsecond pause - enable pulse must be > 450ns + self.delayMicroseconds(1) + self.GPIO.output(self.pin_e, False) + self.delayMicroseconds(1) # commands need > 37us to settle + + def message(self, text): + """ Send string to LCD. Newline wraps to second line""" + + for char in text: + if char == '\n': + self.write4bits(0xC0) # next line + else: + self.write4bits(ord(char), True) \ No newline at end of file diff --git a/leds.py b/leds.py index fa61e41..074e825 100644 --- a/leds.py +++ b/leds.py @@ -7,243 +7,10 @@ # from time import sleep -import neopixel -import board +import lcd_manager +import light_manager -class Adafruit_CharLCD: - - # commands - LCD_CLEARDISPLAY = 0x01 - LCD_RETURNHOME = 0x02 - LCD_ENTRYMODESET = 0x04 - LCD_DISPLAYCONTROL = 0x08 - LCD_CURSORSHIFT = 0x10 - LCD_FUNCTIONSET = 0x20 - LCD_SETCGRAMADDR = 0x40 - LCD_SETDDRAMADDR = 0x80 - - # flags for display entry mode - LCD_ENTRYRIGHT = 0x00 - LCD_ENTRYLEFT = 0x02 - LCD_ENTRYSHIFTINCREMENT = 0x01 - LCD_ENTRYSHIFTDECREMENT = 0x00 - - # flags for display on/off control - LCD_DISPLAYON = 0x04 - LCD_DISPLAYOFF = 0x00 - LCD_CURSORON = 0x02 - LCD_CURSOROFF = 0x00 - LCD_BLINKON = 0x01 - LCD_BLINKOFF = 0x00 - - # flags for display/cursor shift - LCD_DISPLAYMOVE = 0x08 - LCD_CURSORMOVE = 0x00 - - # flags for display/cursor shift - LCD_DISPLAYMOVE = 0x08 - LCD_CURSORMOVE = 0x00 - LCD_MOVERIGHT = 0x04 - LCD_MOVELEFT = 0x00 - - # flags for function set - LCD_8BITMODE = 0x10 - LCD_4BITMODE = 0x00 - LCD_2LINE = 0x08 - LCD_1LINE = 0x00 - LCD_5x10DOTS = 0x04 - LCD_5x8DOTS = 0x00 - - def __init__(self, pin_rs=24, pin_e=23, pin_b=4, pins_db=[17, 25, 27, 22], GPIO=None): - # Emulate the old behavior of using RPi.GPIO if we haven't been given - # an explicit GPIO interface to use - if not GPIO: - import RPi.GPIO as GPIO - self.GPIO = GPIO - self.pin_rs = pin_rs - self.pin_e = pin_e - self.pin_b = pin_b - self.pins_db = pins_db - - self.GPIO.setwarnings(False) - self.GPIO.setmode(GPIO.BCM) - self.GPIO.setup(self.pin_e, GPIO.OUT) - self.GPIO.setup(self.pin_rs, GPIO.OUT) - self.GPIO.setup(self.pin_b, GPIO.OUT) - - for pin in self.pins_db: - self.GPIO.setup(pin, GPIO.OUT) - - self.GPIO.output(self.pin_b, True) - - self.write4bits(0x33) # initialization - self.write4bits(0x32) # initialization - self.write4bits(0x28) # 2 line 5x7 matrix - self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor - self.write4bits(0x06) # shift cursor right - - self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF - - self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS - self.displayfunction |= self.LCD_2LINE - - """ Initialize to default text direction (for romance languages) """ - self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT - self.write4bits(self.LCD_ENTRYMODESET | - self.displaymode) # set the entry mode - - self.clear() - - def begin(self, cols, lines): - - if (lines > 1): - self.numlines = lines - self.displayfunction |= self.LCD_2LINE - self.currline = 0 - - def home(self): - - self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero - self.delayMicroseconds(3000) # this command takes a long time! - - def clear(self): - - self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display - # 3000 microsecond sleep, clearing the display takes a long time - self.delayMicroseconds(3000) - - def setCursor(self, col, row): - - self.row_offsets = [0x00, 0x40, 0x14, 0x54] - - if (row > self.numlines): - row = self.numlines - 1 # we count rows starting w/0 - - self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row])) - - def noDisplay(self): - """ Turn the display off (quickly) """ - self.GPIO.output(self.pin_b, False) - self.displaycontrol &= ~self.LCD_DISPLAYON - self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) - - def display(self): - """ Turn the display on (quickly) """ - self.GPIO.output(self.pin_b, True) - self.displaycontrol |= self.LCD_DISPLAYON - self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) - - def noCursor(self): - """ Turns the underline cursor on/off """ - - self.displaycontrol &= ~self.LCD_CURSORON - self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) - - def cursor(self): - """ Cursor On """ - - self.displaycontrol |= self.LCD_CURSORON - self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) - - def noBlink(self): - """ Turn on and off the blinking cursor """ - - self.displaycontrol &= ~self.LCD_BLINKON - self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) - - def noBlink(self): - """ Turn on and off the blinking cursor """ - - self.displaycontrol &= ~self.LCD_BLINKON - self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol) - - def DisplayLeft(self): - """ These commands scroll the display without changing the RAM """ - - self.write4bits(self.LCD_CURSORSHIFT | - self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT) - - def scrollDisplayRight(self): - """ These commands scroll the display without changing the RAM """ - - self.write4bits(self.LCD_CURSORSHIFT | - self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT) - - def leftToRight(self): - """ This is for text that flows Left to Right """ - - self.displaymode |= self.LCD_ENTRYLEFT - self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) - - def rightToLeft(self): - """ This is for text that flows Right to Left """ - self.displaymode &= ~self.LCD_ENTRYLEFT - self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) - - def autoscroll(self): - """ This will 'right justify' text from the cursor """ - - self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT - self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) - - def noAutoscroll(self): - """ This will 'left justify' text from the cursor """ - - self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT - self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) - - def write4bits(self, bits, char_mode=False): - """ Send command to LCD """ - - self.delayMicroseconds(1000) # 1000 microsecond sleep - - bits = bin(bits)[2:].zfill(8) - - self.GPIO.output(self.pin_rs, char_mode) - - for pin in self.pins_db: - self.GPIO.output(pin, False) - - for i in range(4): - if bits[i] == "1": - self.GPIO.output(self.pins_db[::-1][i], True) - - self.pulseEnable() - - for pin in self.pins_db: - self.GPIO.output(pin, False) - - for i in range(4, 8): - if bits[i] == "1": - self.GPIO.output(self.pins_db[::-1][i-4], True) - - self.pulseEnable() - - def delayMicroseconds(self, microseconds): - # divide microseconds by 1 million for seconds - seconds = microseconds / float(1000000) - sleep(seconds) - - def pulseEnable(self): - self.GPIO.output(self.pin_e, False) - # 1 microsecond pause - enable pulse must be > 450ns - self.delayMicroseconds(1) - self.GPIO.output(self.pin_e, True) - # 1 microsecond pause - enable pulse must be > 450ns - self.delayMicroseconds(1) - self.GPIO.output(self.pin_e, False) - self.delayMicroseconds(1) # commands need > 37us to settle - - def message(self, text): - """ Send string to LCD. Newline wraps to second line""" - - for char in text: - if char == '\n': - self.write4bits(0xC0) # next line - else: - self.write4bits(ord(char), True) - debug_statements = True @@ -270,7 +37,8 @@ def color(lcd): def loop(): - lcd = Adafruit_CharLCD() + lcd = lcd_manager.Adafruit_CharLCD() + lights = light_manager.LightStrip() level = 0 level_max = 14 idle = 0 @@ -281,6 +49,7 @@ def loop(): query_level = querylightlevel() idle = idle + 1 debug("idle value: {}".format(idle)) + lights.tick() if query_level != level: level = query_level lights.set_light_level(level / level_max) diff --git a/light_manager.py b/light_manager.py index e69de29..bb8884b 100644 --- a/light_manager.py +++ b/light_manager.py @@ -0,0 +1,31 @@ +from time import sleep +import neopixel +import board + +def defaultPattern(n, t): + return (255, 0, 200) + +class LightStrip: + def __init__(self, data_pin = board.D18, string_length = 300, brightness = 1, pixel_order = neopixel.GRB): + self.data_pin = data_pin + + self.np = neopixel.NeoPixel(self.data_pin, string_length, brightness = brightness, auto_write=True, pixel_order = pixel_order) + self.pattern = defaultPattern + self.cur_tick = 0 + + def set_light_level(self, level): + self.np.brightness = level + def pattern(self, pattern_callback): + self.pattern = pattern_callback + + def tick(self): + np = self.np + t = self.cur_tick + n = np.n + for i in range(n): + col = self.pattern(i, t) + if np[i] != col: + #np[i] = col + print("CHANGE COLOR OF PIXEL {} ON TICK {}".format(col, t)) + break; + self.cur_tick = t + 1 \ No newline at end of file