Browse Source

Adding FA Bezel Dongle LED Control Script

Wrote a nicer script in Python to control the FA Bezel Dongle LEDs
master
Nate Bohman 6 years ago
parent
commit
04aaec7251
2 changed files with 173 additions and 0 deletions
  1. +2
    -0
      fa_bezel_led/requirements.txt
  2. +171
    -0
      fa_bezel_led/set_led.py

+ 2
- 0
fa_bezel_led/requirements.txt View File

@@ -0,0 +1,2 @@
pylibftdi
six

+ 171
- 0
fa_bezel_led/set_led.py View File

@@ -0,0 +1,171 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse
import logging

from pylibftdi import BitBangDevice
from pylibftdi._base import FtdiError
from pylibftdi.device import Driver
import six

__author__ = "Nate Bohman"
__credits__ = ["Nate Bohman"]
__license__ = "LGPL"
__maintainer__ = "Nate Bohman"
__email__ = "natrinicle@gmail.com"
__status__ = "Development"

logger = logging.getLogger(__name__) # pylint: disable=invalid-name


FAR_LED = {"ON": 0, "MID": 1, "OFF": 21}
NEAR_LED = {"ON": 0, "MID": 2, "OFF": 42}


def set_led(serial_num=None, far_led=None, near_led=None):
"""Set the LEDs on an FTDI BitBanged device.

:param serial_num: (optional) Serial number of the FTDI
device or None to use the first
available device.
:param far_led: (optional) Set the LED furthest from the USB
connector to ON, MID, or OFF.
:param near_led: (optional) Set the LED closest to the USB
connector to ON, MID, or OFF.
:type serial_num: :class:`str` or None
:type far_led: :class:`str`
:type near_led: :class:`str`
"""
if serial_num is not None:
assert isinstance(serial_num, (six.string_types))
if far_led is not None:
far_led = FAR_LED.get(far_led.upper())
assert isinstance(far_led, (int))
if near_led is not None:
near_led = NEAR_LED.get(near_led.upper())
assert isinstance(near_led, (int))

try:
with BitBangDevice(serial_num) as bb:
if far_led is None:
# Binary bitwise and the current state against the
# bits that are significant to the far_led.
far_led = bb.read_pins() & 21
if near_led is None:
# Binary bitwise and the current state against the
# bits that are significant to the near_led.
near_led = bb.read_pins() & 42

serial = Driver().list_devices()[bb.device_index][2].decode()

log_msg = "Setting {} far led to {}, near_led to {}".format(
serial,
[key for key in FAR_LED if FAR_LED[key] == far_led][0],
[key for key in NEAR_LED if NEAR_LED[key] == near_led][0],
)
logger.info(log_msg)
bb.port = far_led | near_led
except FtdiError as e:
if "usb_open() failed" in str(e):
err_msg = "".join(
[
"Could not open any FTDI devices. Check permissions and ",
"potentially add the following to udev rules "
'\'SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ',
'ATTRS{idProduct}=="6001", MODE="0666"\' ',
"or ensure the LED dongle is attached to the system.",
]
)
raise EnvironmentError((-4, err_msg))


def configure_logging(logger, verbosity):
"""Take an int and configures logger levels accordingly where 0 = ERROR and 3 = DEBUG.

:param logger: Logger object to configure.
:param verbosity: Integer coresponding to logging level from 0 being ERROR and 3 being DEBUG.
:type logger: :class:`logging.Logger`
:type verbosity: :class:`int`
"""
assert isinstance(logger, (logging.Logger))
assert isinstance(verbosity, (int))

# The messages that display are controlled by the -v or -vv arguments in parse_arguments with
# defaults being error or worse. A single v includes warning messages, a double v includes info
# messages, and a triple v includes debug messages. Triple v also changes the log_format to
# include the module, function name, and line number where logger was called from.
#
# Verbosity
# parser.add_argument("-v", "--verbose", dest="verbose", action="count", default=0,)

log_levels = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG]
log_level = log_levels[
min(len(log_levels) - 1, verbosity)
] # capped to number of levels
if log_level > logging.DEBUG:
log_format = "%(asctime)s %(levelname)s %(message)s"
else:
log_format = (
"%(asctime)s %(levelname)s %(module)s %(funcName)s:%(lineno)s %(message)s"
)

logging.basicConfig(format=log_format)
logger.setLevel(level=log_level)


def parse_args():
"""Parse Arguments for set_led."""
parser = argparse.ArgumentParser(
description="Set PureStorage Front Panel LED module states."
)

# Base information (usernames, passwords, etc...)
parser.add_argument(
"-s",
"--serial-num",
dest="serial_num",
action="store",
required=False,
help="Serial Number of LED module if more than one installed.",
)
parser.add_argument(
"-f",
"--far-led",
dest="far_led",
action="store",
required=False,
type=str,
help="State to set the LED furthest from the USB connector (ON, MID, OFF).",
)
parser.add_argument(
"-n",
"--near-led",
dest="near_led",
action="store",
required=False,
type=str,
help="State to set the LED closest to the USB connector (ON, MID, OFF).",
)

# Verbosity
parser.add_argument("-v", "--verbose", dest="verbose", action="count", default=0)

# Positional arguments

args = parser.parse_args()

# Configure logging
configure_logging(logger=logger, verbosity=args.verbose)

return args


def main():
"""Main function that is called when script directly called."""
args = parse_args()
set_led(serial_num=args.serial_num, far_led=args.far_led, near_led=args.near_led)


if __name__ == "__main__":
main()

Loading…
Cancel
Save