Skip to content

Utilities Overview

The pydoover.utils module provides a collection of utility functions and classes that simplify common tasks in pydoover applications. These utilities cover async/sync abstraction, signal processing, state management, and data manipulation.

Module Exports

All utilities are available directly from pydoover.utils:

from pydoover.utils import (
    # Async/Sync helpers
    call_maybe_async,
    maybe_async,
    get_is_async,
    wrap_try_except,
    wrap_try_except_async,

    # Signal processing
    apply_kalman_filter,
    apply_async_kalman_filter,
    PID,

    # Alarms
    create_alarm,

    # Diff operations
    apply_diff,
    generate_diff,
    maybe_load_json,

    # Data structures
    CaseInsensitiveDict,
    CaseInsensitiveDictEncoder,

    # Object searching
    find_object_with_key,
    find_path_to_key,
    map_reading,

    # Logging
    setup_logging,
    LogFormatter,

    # Decorators
    deprecated,
    on_change,
)

# State management
from pydoover.state import StateMachine

Utility Categories

Async/Sync Helpers

Functions and decorators that help write code that works in both synchronous and asynchronous contexts.

FunctionDescription
call_maybe_async()Call a function that may be sync or async
maybe_async()Decorator for unified sync/async method interfaces
get_is_async()Detect if running in async context
wrap_try_except()Exception wrapper for sync functions
wrap_try_except_async()Exception wrapper for async functions

See Async Helpers for detailed documentation.

Signal Processing

Utilities for processing sensor data and implementing control loops.

Class/FunctionDescription
PIDPID controller implementation
apply_kalman_filter()Decorator for Kalman filtering
apply_async_kalman_filter()Async version of Kalman filter decorator

See PID Controller and Kalman Filter for detailed documentation.

Alarm Utilities

State machine for threshold-based alarms with grace periods.

FunctionDescription
create_alarm()Create an alarm that monitors function return values

See Alarms for detailed documentation.

Diff Operations

Functions for generating and applying diffs between dictionaries.

FunctionDescription
apply_diff()Apply a diff to a dictionary
generate_diff()Generate a diff between two dictionaries
maybe_load_json()Attempt to parse JSON, return original on failure

See Diff Utilities for detailed documentation.

Data Structures

Specialized data structures for common patterns.

ClassDescription
CaseInsensitiveDictDictionary with case-insensitive keys
CaseInsensitiveDictEncoderJSON encoder for CaseInsensitiveDict

Object Searching

Functions for searching through nested dictionaries.

FunctionDescription
find_object_with_key()Find a value by key in nested dict
find_path_to_key()Find the path to a key in nested dict
map_reading()Map sensor readings to output ranges

Logging

Utilities for configuring application logging.

Function/ClassDescription
setup_logging()Configure logging with optional formatters
LogFormatterColor-coded log formatter

Decorators

General-purpose decorators.

DecoratorDescription
deprecated()Mark functions/classes as deprecated
on_change()Trigger callback when return value changes

State Management

The StateMachine class from pydoover.state provides a wrapper around the transitions library for managing application state with timeouts.

ClassDescription
StateMachineState machine with timeout support and async callbacks

See State Machine for detailed documentation.

Quick Examples

Setting Up Logging

from pydoover.utils import setup_logging

# Enable debug logging
setup_logging(debug=True)

# Standard info logging
setup_logging(debug=False)

Case-Insensitive Dictionary

from pydoover.utils import CaseInsensitiveDict

config = CaseInsensitiveDict()
config["API_KEY"] = "secret123"

# All of these access the same value
print(config["api_key"])    # "secret123"
print(config["Api_Key"])    # "secret123"
print(config["API_KEY"])    # "secret123"

Finding Values in Nested Structures

from pydoover.utils import find_object_with_key, find_path_to_key

data = {
    "sensors": {
        "temperature": {
            "value": 23.5,
            "unit": "celsius"
        }
    }
}

# Find the value
value = find_object_with_key(data, "value")
print(value)  # 23.5

# Find the path to the key
path = find_path_to_key(data, "value")
print(path)  # "sensors.temperature.value"

Mapping Sensor Readings

from pydoover.utils import map_reading

# Map a 4-20mA reading to a 0-100 range
raw_value = 12  # mA
output_values = [0, 100]
raw_readings = [4, 20]

mapped = map_reading(raw_value, output_values, raw_readings)
print(mapped)  # 50.0

Deprecation Decorator

from pydoover.utils import deprecated

@deprecated("Use new_function() instead")
def old_function():
    pass

@deprecated
def another_old_function():
    pass

On Change Callback

from pydoover.utils import on_change

class SensorMonitor:
    def handle_change(self, new_val, old_val, is_first, name):
        if not is_first:
            print(f"{name} changed from {old_val} to {new_val}")

    @on_change("handle_change", name="temperature")
    def read_temperature(self):
        # Return current temperature
        return self.sensor.read()

Related Pages