Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ name: CI
jobs:

test:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
matrix:
deps:
Expand All @@ -32,3 +32,17 @@ jobs:
run: pip install -r requirements-dev.txt
- name: Run tests
run: pytest

format:
runs-on: ubuntu-24.04
name: Check code formatting with black
steps:
- uses: actions/checkout@v3
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: 3.12
- name: Install black
run: pip install black~=25.1
- name: Check code formatting
run: black --check .
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ Coding Guidelines

flake8 --max-line-length=99 --ignore=E126,E127,E128,C901 RPLCD/lcd.py

Additionally, please reformat your code using `black <https://black.readthedocs.io/>`_::

black .


About HD44780
=============
Expand Down
7 changes: 5 additions & 2 deletions RPLCD/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
class CharLCD:
def __new__(cls, *args, **kwargs):
from .gpio import CharLCD as GpioCharLCD
warnings.warn("Using RPLCD.CharLCD directly is deprecated. " +
"Use RPLCD.gpio.CharLCD instead!", DeprecationWarning)

warnings.warn(
"Using RPLCD.CharLCD directly is deprecated. Use RPLCD.gpio.CharLCD instead!",
DeprecationWarning,
)
return GpioCharLCD(*args, **kwargs)
7 changes: 3 additions & 4 deletions RPLCD/codecs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class FoundMultiCharMapping(Exception):
"""
Exception to escape nested loops.
"""

pass


Expand All @@ -25,8 +26,7 @@ def __init__(self, codec):

def encode(self, input_): # type: (str) -> List[int]
result = []
window_iter = sliding_window(
input_, self.codec.combined_chars_lookahead)
window_iter = sliding_window(input_, self.codec.combined_chars_lookahead)
while True:
try:
window = next(window_iter)
Expand Down Expand Up @@ -60,8 +60,7 @@ def encode(self, input_): # type: (str) -> List[int]
continue

# Otherwise, do a regular lookup in the encoding table
result.append(self.codec.encoding_table.get(
char, self.codec.replacement_char))
result.append(self.codec.encoding_table.get(char, self.codec.replacement_char))

return result

Expand Down
5 changes: 4 additions & 1 deletion RPLCD/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""

import itertools
import time

Expand Down Expand Up @@ -72,7 +73,8 @@
RS_DATA = 0x01


# # # Helper classes # # #
# # # HELPER CLASSES # # #


class Alignment(object):
left = LCD_ENTRYLEFT
Expand All @@ -92,6 +94,7 @@ class CursorMode(object):

# # # HELPER FUNCTIONS # # #


def msleep(milliseconds):
"""Sleep the specified amount of milliseconds."""
time.sleep(milliseconds / 1000.0)
Expand Down
91 changes: 63 additions & 28 deletions RPLCD/gpio.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""

from collections import namedtuple

import RPi.GPIO as GPIO
Expand All @@ -35,13 +36,23 @@


class CharLCD(BaseCharLCD):
def __init__(self, numbering_mode=None, pin_rs=None, pin_rw=None, pin_e=None, pins_data=None,
pin_backlight=None, backlight_mode='active_low',
backlight_enabled=True,
cols=20, rows=4, dotsize=8,
charmap='A02',
auto_linebreaks=True,
compat_mode=False):
def __init__(
self,
numbering_mode=None,
pin_rs=None,
pin_rw=None,
pin_e=None,
pins_data=None,
pin_backlight=None,
backlight_mode='active_low',
backlight_enabled=True,
cols=20,
rows=4,
dotsize=8,
charmap='A02',
auto_linebreaks=True,
compat_mode=False,
):
"""
Character LCD controller.

Expand Down Expand Up @@ -100,10 +111,12 @@ def __init__(self, numbering_mode=None, pin_rs=None, pin_rw=None, pin_e=None, pi
if numbering_mode == GPIO.BCM or numbering_mode == GPIO.BOARD:
self.numbering_mode = numbering_mode
else:
raise ValueError('Invalid GPIO numbering mode: numbering_mode=%s, '
'must be either GPIO.BOARD or GPIO.BCM.\n'
'See https://gist.github.com/dbrgn/77d984a822bfc9fddc844f67016d0f7e '
'for more details.' % numbering_mode)
raise ValueError(
'Invalid GPIO numbering mode: numbering_mode=%s, '
'must be either GPIO.BOARD or GPIO.BCM.\n'
'See https://gist.github.com/dbrgn/77d984a822bfc9fddc844f67016d0f7e '
'for more details.' % numbering_mode
)
if pin_rs is None:
raise ValueError('pin_rs is not defined.')
if pin_e is None:
Expand All @@ -118,17 +131,27 @@ def __init__(self, numbering_mode=None, pin_rs=None, pin_rw=None, pin_e=None, pi
else:
raise ValueError('There should be exactly 4 or 8 data pins.')
block2 = pins_data[-4:]
self.pins = PinConfig(rs=pin_rs, rw=pin_rw, e=pin_e,
d0=block1[0], d1=block1[1], d2=block1[2], d3=block1[3],
d4=block2[0], d5=block2[1], d6=block2[2], d7=block2[3],
backlight=pin_backlight,
mode=numbering_mode)
self.pins = PinConfig(
rs=pin_rs,
rw=pin_rw,
e=pin_e,
d0=block1[0],
d1=block1[1],
d2=block1[2],
d3=block1[3],
d4=block2[0],
d5=block2[1],
d6=block2[2],
d7=block2[3],
backlight=pin_backlight,
mode=numbering_mode,
)
self.backlight_mode = backlight_mode

# Call superclass
super(CharLCD, self).__init__(cols, rows, dotsize,
charmap=charmap,
auto_linebreaks=auto_linebreaks)
super(CharLCD, self).__init__(
cols, rows, dotsize, charmap=charmap, auto_linebreaks=auto_linebreaks
)

# Set backlight status
if pin_backlight is not None:
Expand All @@ -150,9 +173,19 @@ def _init_connection(self):
GPIO.output(self.pins.rw, 0)

def _close_connection(self):
pins = (self.pins.rs, self.pins.rw, self.pins.e, self.pins.d0, self.pins.d1,
self.pins.d2, self.pins.d3, self.pins.d4, self.pins.d5, self.pins.d6,
self.pins.d7)
pins = (
self.pins.rs,
self.pins.rw,
self.pins.e,
self.pins.d0,
self.pins.d1,
self.pins.d2,
self.pins.d3,
self.pins.d4,
self.pins.d5,
self.pins.d6,
self.pins.d7,
)
active_pins = [pin for pin in pins if pin is not None]
GPIO.cleanup(active_pins)

Expand All @@ -171,11 +204,13 @@ def _set_backlight_enabled(self, value):
if not isinstance(value, bool):
raise ValueError('backlight_enabled must be set to ``True`` or ``False``.')
self._backlight_enabled = value
GPIO.output(self.pins.backlight,
value ^ (self.backlight_mode == 'active_low'))
GPIO.output(self.pins.backlight, value ^ (self.backlight_mode == 'active_low'))

backlight_enabled = property(_get_backlight_enabled, _set_backlight_enabled,
doc='Whether or not to turn on the backlight.')
backlight_enabled = property(
_get_backlight_enabled,
_set_backlight_enabled,
doc='Whether or not to turn on the backlight.',
)

# Low level commands

Expand Down Expand Up @@ -205,11 +240,11 @@ def _send(self, value, mode):
self.last_send_event = now()

def _send_data(self, value):
"""Send data to the display. """
"""Send data to the display."""
self._send(value, c.RS_DATA)

def _send_instruction(self, value):
"""Send instruction to the display. """
"""Send instruction to the display."""
self._send(value, c.RS_INSTRUCTION)

def _write4bits(self, value):
Expand Down
63 changes: 41 additions & 22 deletions RPLCD/i2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""

try:
from smbus import SMBus
except ImportError:
Expand All @@ -38,7 +39,7 @@

# MCP230XX backlight control
MCP230XX_BACKLIGHT = 0x80
MCP230XX_NOBACKLIGHT = 0x7f
MCP230XX_NOBACKLIGHT = 0x7F

# MCP230XX pin bitmasks and datamask
MCP230XX_RS = 0x02
Expand All @@ -58,11 +59,19 @@


class CharLCD(BaseCharLCD):
def __init__(self, i2c_expander, address, expander_params=None, port=1,
cols=20, rows=4, dotsize=8,
charmap='A02',
auto_linebreaks=True,
backlight_enabled=True):
def __init__(
self,
i2c_expander,
address,
expander_params=None,
port=1,
cols=20,
rows=4,
dotsize=8,
charmap='A02',
auto_linebreaks=True,
backlight_enabled=True,
):
"""
CharLCD via PCF8574 I2C port expander:

Expand Down Expand Up @@ -93,7 +102,7 @@ def __init__(self, i2c_expander, address, expander_params=None, port=1,
Pin mapping::

7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
-- | -- | -- | -- | -- | - | -- | -
-- | -- | -- | -- | -- | - | -- | -
BL | D7 | D6 | D5 | D4 | E | RS | -


Expand Down Expand Up @@ -138,8 +147,10 @@ def __init__(self, i2c_expander, address, expander_params=None, port=1,
# Errorchecking for expander parameters
if expander_params is None:
if self._i2c_expander == 'MCP23017':
raise ValueError('MCP23017: expander_params[\'gpio_bank\'] is not defined, '
'must be either \'A\' or \'B\'')
raise ValueError(
'MCP23017: expander_params[\'gpio_bank\'] is not defined, '
'must be either \'A\' or \'B\''
)
else:
self._expander_params = {}
else:
Expand All @@ -148,8 +159,10 @@ def __init__(self, i2c_expander, address, expander_params=None, port=1,
self._expander_params = {}
self._expander_params['gpio_bank'] = expander_params['gpio_bank']
else:
raise ValueError('MCP23017: expander_params[\'gpio_bank\'] is \'%s\', '
'must be either \'A\' or \'B\'' % expander_params['gpio_bank'])
raise ValueError(
'MCP23017: expander_params[\'gpio_bank\'] is \'%s\', '
'must be either \'A\' or \'B\'' % expander_params['gpio_bank']
)

# Currently the I2C mode only supports 4 bit communication
self.data_bus_mode = c.LCD_4BITMODE
Expand All @@ -161,9 +174,9 @@ def __init__(self, i2c_expander, address, expander_params=None, port=1,
self._backlight = MCP230XX_BACKLIGHT if backlight_enabled else MCP230XX_NOBACKLIGHT

# Call superclass
super(CharLCD, self).__init__(cols, rows, dotsize,
charmap=charmap,
auto_linebreaks=auto_linebreaks)
super(CharLCD, self).__init__(
cols, rows, dotsize, charmap=charmap, auto_linebreaks=auto_linebreaks
)
# Refresh backlight status
self.backlight_enabled = backlight_enabled

Expand Down Expand Up @@ -216,17 +229,21 @@ def _set_backlight_enabled(self, value):
self._mcp_data &= MCP230XX_NOBACKLIGHT
self.bus.write_byte_data(self._address, self._mcp_gpio, self._mcp_data)

backlight_enabled = property(_get_backlight_enabled, _set_backlight_enabled,
doc='Whether or not to enable the backlight. Either ``True`` or ``False``.')
backlight_enabled = property(
_get_backlight_enabled,
_set_backlight_enabled,
doc='Whether or not to enable the backlight. Either ``True`` or ``False``.',
)

# Low level commands

def _send_data(self, value):
if self._i2c_expander == 'PCF8574':
self.bus.write_byte(self._address, (c.RS_DATA | (value & 0xF0)) | self._backlight)
self._pulse_data(c.RS_DATA | (value & 0xF0))
self.bus.write_byte(self._address, (c.RS_DATA |
((value << 4) & 0xF0)) | self._backlight)
self.bus.write_byte(
self._address, (c.RS_DATA | ((value << 4) & 0xF0)) | self._backlight
)
self._pulse_data(c.RS_DATA | ((value << 4) & 0xF0))
elif self._i2c_expander in ['MCP23008', 'MCP23017']:
self._mcp_data |= MCP230XX_RS
Expand All @@ -235,11 +252,13 @@ def _send_data(self, value):

def _send_instruction(self, value):
if self._i2c_expander == 'PCF8574':
self.bus.write_byte(self._address, (c.RS_INSTRUCTION |
(value & 0xF0)) | self._backlight)
self.bus.write_byte(
self._address, (c.RS_INSTRUCTION | (value & 0xF0)) | self._backlight
)
self._pulse_data(c.RS_INSTRUCTION | (value & 0xF0))
self.bus.write_byte(self._address, (c.RS_INSTRUCTION |
((value << 4) & 0xF0)) | self._backlight)
self.bus.write_byte(
self._address, (c.RS_INSTRUCTION | ((value << 4) & 0xF0)) | self._backlight
)
self._pulse_data(c.RS_INSTRUCTION | ((value << 4) & 0xF0))
elif self._i2c_expander in ['MCP23008', 'MCP23017']:
self._mcp_data &= ~MCP230XX_RS
Expand Down
Loading