Skip to main content

Integration with the meticulouscoffee machine via its REST API

Project description

pyMeticulous

A comprehensive Python wrapper for the Meticulous espresso machine API.

License: GPL v3

Overview

pyMeticulous provides a complete Python interface to the Meticulous TypeScript API, enabling programmatic control and monitoring of Meticulous espresso machines.

Version 0.3.0 adds complete backend API alignment with comprehensive testing, event throttling, robust error handling, and extensive machine management endpoints.

Features

  • Profile Management: Create, load, save, and manage espresso profiles
  • Real-time Monitoring: Socket.IO integration for live brewing data
  • Shot History: Search, track, rate, and retrieve shot logs (with .zst decompression)
  • Device Control: Execute actions (start, stop, tare, preheat, calibration)
  • WiFi Management: Configure network settings and scan available networks
  • Settings Control: Manage machine settings and preferences
  • Firmware Updates: Upload and install firmware updates
  • Sound Themes: Control sound playback and themes
  • Type Safety: Pydantic models with full validation
  • Comprehensive Error Handling: All methods return typed responses or errors

Installation

You can install the pyMeticulous package using pip:

pip install pyMeticulous

Quick Start

from meticulous.api import Api
from meticulous.api_types import ActionType

# Initialize the API client
api = Api(base_url="http://localhost:8080/")

# Get device information
device = api.get_device_info()
print(f"Connected to: {device.name}")

# List available profiles
profiles = api.list_profiles()
for profile in profiles:
    print(f"Profile: {profile.name}")

# Load and start a profile
api.load_profile_by_id(profiles[0].id)
api.execute_action(ActionType.START)

API Reference

For complete API documentation including all endpoints, parameters, and return types, see the API Specification.

Key capabilities:

  • Profile management (list, load, save, delete)
  • Real-time brewing data via Socket.IO
  • Shot history search, logs (.zst decompression), and statistics
  • Machine control (start, stop, tare, preheat, calibration)
  • WiFi configuration and network scanning
  • Settings management
  • Firmware updates
  • Device information and diagnostics

Examples

The examples/ directory contains several demonstration scripts:

Basic Profile Management

# examples/load_change_and_execute.py
# Demonstrates loading profiles, modifying them, and executing brewing

Socket.IO Real-time Events

# examples/connect_socketio.py
# Shows how to connect to real-time brewing events

Device Information and Statistics

# examples/device_info_and_stats.py
# Get device details and shot history statistics

History Search and Rating

# examples/history_search_and_rating.py
# Search shot history, filter by date, and rate shots

WiFi Management

# examples/wifi_management.py
# Manage WiFi connections and scan networks

Real-time Events

Subscribe to real-time brewing events using Socket.IO:

from meticulous.api import Api, ApiOptions

def on_status(data):
    print(f"State: {data.state}, Time: {data.profile_time}ms")

def on_temperatures(data):
    print(f"Boiler: {data.t_bar_up}°C")

# Configure event handlers
options = ApiOptions(
    onStatus=on_status,
    onTemperatureSensors=on_temperatures
)

api = Api(base_url="http://localhost:8080/", options=options)
api.connect_to_socket()

# Events will now fire automatically
# ... do work ...

api.disconnect_socket()

Event Throttling

To avoid overloading your handlers with high-frequency events, enable simple throttling via ApiOptions.throttle:

from meticulous.api import Api, ApiOptions

def on_status(data):
    # Will be called at most once every 250ms
    print(f"State: {data.state}, Time: {data.profile_time}ms")

# Throttle all events globally to 250ms
api = Api(
    base_url="http://localhost:8080/",
    options=ApiOptions(onStatus=on_status, throttle=0.25)
)

# Or throttle individual events by name
api = Api(
    options=ApiOptions(
        onStatus=on_status,
        throttle={"status": 0.25, "temperature": 0.5}
    )
)

Socket.IO Helpers

Convenience helpers are available for emitting common actions over Socket.IO:

from meticulous.api_types import ActionType

api.send_action_socketio(ActionType.START)
api.acknowledge_notification_socketio("notif-id", "acknowledged")
api.send_profile_hover({"id": "profile-id", "name": "My Profile"})
api.trigger_calibration(True)

Error Handling

All API methods return either the expected type or an APIError object:

from meticulous.api_types import APIError

result = api.get_profile("some-id")

if isinstance(result, APIError):
    print(f"Error: {result.error}")
    if result.description:
        print(f"Details: {result.description}")
else:
    # Success - result is a Profile object
    print(f"Profile loaded: {result.name}")

Union Returns

Some methods can return more than one success shape depending on firmware version or endpoint:

  • WiFi config: get_wifi_config()WiFiConfigResponse (wrapped with status) or WiFiConfig (bare config)
  • Default profiles: get_default_profiles()DefaultProfiles (grouped) or List[Profile]
  • Current/last shot: get_current_shot() / get_last_shot()HistoryEntry or None

Always guard with isinstance(...) checks in your code and tests.

Type Safety

pyMeticulous uses Pydantic v2 for complete data validation and type safety. All API methods accept and return fully typed models. See the Type Reference section in the API specification for complete model documentation.

Development

Running Tests

pyMeticulous includes both unit tests (fast, using mocks) and integration tests (require real hardware).

# Install test dependencies
pip install -e ".[test]"

# Run only unit tests (fast, no hardware needed)
pytest -m "not integration"

# Run only integration tests (requires real machine)
export METICULOUS_HOST=192.168.1.100:8080  # Set your machine address
pytest -m integration

# Run all tests
pytest

# Run with coverage (unit tests only)
pytest --cov=meticulous -m "not integration"

Test Organization

  • Unit Tests (tests/test_*.py) - Fast tests using mocks, run on every change

    • test_models.py - Type model validation
    • test_rest_api.py - REST endpoint tests
    • test_socketio.py - Socket.IO functionality
  • Integration Tests (tests/integration/) - Validate against real hardware

    • test_api_endpoints.py - REST API validation
    • test_safe_posts.py - Safe POST operations
    • test_socketio.py - Real-time event streaming

See tests/integration/README.md for integration test details.

Project Structure

pyMeticulous/
├── meticulous/
│   ├── __init__.py
│   ├── api.py              # Main API client
│   ├── api_types.py        # Type definitions
│   └── profile.py          # Profile model
├── tests/
│   ├── test_models.py      # Model/type tests
│   ├── test_rest_api.py    # REST API tests
│   ├── test_socketio.py    # Socket.IO tests
│   ├── integration/        # Integration tests (require real machine)
│   └── mock_responses.py   # Test fixtures
├── examples/               # Example scripts
├── API_SPEC.md            # Complete API documentation
├── README.md
└── pyproject.toml

Requirements

  • Python >= 3.11
  • requests >= 2.32.3
  • pydantic >= 2.7.3
  • python-socketio >= 5.11.2
  • websocket-client >= 1.8.0
  • zstandard >= 0.22.0 (for shot log decompression)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Related Projects

License

GPL-3.0 License - see LICENSE file for details

Support

For issues, questions, or feature requests:

Changelog

See CHANGELOG.md for full release notes.

Acknowledgments

This project is a Python wrapper for the Meticulous espresso machine API. Thanks to the Meticulous team for creating an open and well-documented API.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymeticulous-0.3.1.tar.gz (37.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pymeticulous-0.3.1-py3-none-any.whl (25.9 kB view details)

Uploaded Python 3

File details

Details for the file pymeticulous-0.3.1.tar.gz.

File metadata

  • Download URL: pymeticulous-0.3.1.tar.gz
  • Upload date:
  • Size: 37.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pymeticulous-0.3.1.tar.gz
Algorithm Hash digest
SHA256 cfa7b0bef17e98413266c4fe2c07defa301e18472cf2a5ffcffc7250d90ba59b
MD5 2f6b9a715b349a19ee182c74d2edf7c1
BLAKE2b-256 64317d539aacbe69606f31e460f6724c357cfebfa98fdeeb06445837631e62c1

See more details on using hashes here.

File details

Details for the file pymeticulous-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: pymeticulous-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 25.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pymeticulous-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 db3ff2cd8a351c13b9f5f3974a8e99e32c31ca59884c436fa28253912a112fbf
MD5 8139eb28b9350db5c66f610bb65dd63e
BLAKE2b-256 222eb1c46a55f3da336c9c6913e09551d1a11f427c392544d8876faa6af64f81

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page