Random code
Image credit: Stanislav Kondratiev

f451 Labs RPI Common module

Overview

The f451 Labs RPI Common module contains helper functions, variables, and constants that are common for most/all f451 Labs RPI applications. There are 5 main components in this module:

  • CLI UI — contains functions and classes for creating a UI in the terminal based on the ‘Rich’ library
  • Cloud — includes helper classes for interacting with cloud services (e.g. Adafruit IO)
  • Colors — includes RGB values for tons of colors
  • Common — includes miscelaneous help functions, classes, and more
  • Logger — encapsulates the default Python ‘Logging’ class and adds a few more features commonly used in f451 Labs RPI projects.

Core functions

This module includes the following classes and functions:

  • init_cli_parser() — Initialize the ArgParse parser with default CLI arguments.
  • is_valid() — Verify that a given (sensor) value falls within a known valid absolute range.
  • is_in_range() — Verify that a given (sensor) value falls within X% of a known valid range.
  • get_delta_range() — Determine a given (sensor) value is above, below, or within a known range.
  • get_tri_colors() — Get low-normal-high colors from a color map for a given sensor value.
  • load_settings() — Initialize TOML parser and load settings file.
  • get_RPI_serial_num() — Get Raspberry Pi serial number.
  • get_RPI_ID() — Get Raspberry Pi ID. Also allows for additional pre- and/or suffix.
  • check_wifi() — Check for Wi-Fi connection on Raspberry Pi.
  • num_to_range() — Map numeric value to range.
  • convert_to_rgb() — Map numeric value to RGB.
  • convert_to_bool() — Convert value to boolean. Mainly used for config strings (e.g. “yes”, “true”, “on”, etc.).
  • make_logo() — Create fancy logo for CLI apps. This function uses the ‘pyfiglet’ library and the ‘slant’ font to create multi-line ASCII-art logos … you’re welcome! 🤓
  • Runtime — Helper class for creating a global application runtime object.
  • FakeSensor — Helper class for creating fake ‘sensors’ for testing, etc.
  • AdafruitCloud — Main class for interacting with Adafruit IO cloud service.
  • AdafruitFeed — Helper class for managing Adafruit IO feeds.
  • AdafruitCloudError — Helper class for managing IO errors related to Adafruit IO cloud service.
  • Logger — Main class for creating a logger object.
  • prep_data() — Helper function to prep/format data for display via BasUI object.
  • BaseUI — Helper class for creating a terminbal UI with a logo, ‘actions’ section, and data table.
  • Logo — Helper class for creating fancy logos 🤓

Please refer to the GitHub repo for source code and documentation.

Dependencies

This module depends on the following libraries:

How to use

Using the module is straightforward. Simply import the components of the module as needed in your code.

For example, the following code snippet shows how we can include some function from the common module.

# Import specific components from f451 Labs Common module
from f451_common.common import some_function, some_variable, some_constant

myVar = some_function()

# Import all components f451 Labs Common module
import f451_common.common as f451Common

myVar = f451Common.some_function()

This example shows how we can set up a logger.
# Import f451 Labs Logger
from f451_common.logger import Logger

# This is optional, but useful if you want to 
# use predefined constant for logging levels
import logging

# Instantiate using defaults ...
myLogger = Logger()

# ... or with custom log level and log file values
myLogger = Logger(
    logLvl=logging.ERROR, 
    logFile="path/to/mylogfile.log"
)

# Call 'log_xxxx' methods to log messages
myLogger.log_info("Hello world!")
myLogger.log_error("Oops! Something broke :-(")

# Call 'debug' method to show message in console
myLogger.debug("Hello world!")

myVar = 2
myLogger.debug(myVar)

Here is an example of how we can use the library to work with a cloud service:
# Import f451 Labs Cloud
from f451_common.cloud import AdafruitCloud

# Initialize 'Cloud'
myPuffyCloud = AdafruitCloud(
    AIO_ID = "<ADAFRUIT IO USERNAME>", 
    AIO_KEY = "<ADAFRUIT IO KEY>"
)

# Create an Adafruit IO feed
feed = myPuffyCloud.create_feed('my-new-feed')

# Upload data to Adafruit IO feed
asyncio.run(myPuffyCloud.send_data(feed.key, randint(1, 100)))

# Receiving latest data from Adafruit IO feed
data = asyncio.run(myPuffyCloud.receive_data(feed.key, True))

# Adafruit IO returns data in form of 'namedtuple' and we can 
# use the '_asdict()' method to convert it to regular 'dict'.
# We then pass the 'dict' to 'json.dumps()' to prettify before 
# we print out the whole structure.
pretty = json.dumps(data._asdict(), indent=4, sort_keys=True)
print(pretty)

Of course, the real value of these helper classes and functions is that we can attach them to a global application runtime object. I use that technique to avoid managing a whole slew of global variables.

Many of my applications have to keep track of many different counters, states, and more, and keeping most/all of them within a single application runtime object makes it easier to streamline the code.

Please refer to the README file in the repo for more detailed information about this library. Also check my posts on the sysmon, sensemon, and enviromon applications where I use this technique.