Skip to content

Quality Scale Guide

L3DigitalNet edited this page Feb 7, 2026 · 1 revision

Quality Scale Guide

Guide to achieving Bronze, Silver, Gold, and Platinum tiers in the Home Assistant Integration Quality Scale.

Overview

The Integration Quality Scale measures integration quality across four tiers. Higher tiers indicate better reliability, maintainability, and user experience.

Why it matters:

  • Users trust higher-tier integrations
  • Core integrations must meet minimum standards
  • Community integrations benefit from quality benchmarks
  • HACS may require Bronze tier minimum

Tier Progression

Bronze → Silver → Gold → Platinum
  ↓       ↓        ↓        ↓
Basic   Reliable  Robust  Excellent

Each tier builds on the previous. You must meet ALL requirements of lower tiers.


Bronze Tier (Minimum Viable Integration)

Goal: Functional integration with basic quality standards.

Requirements

✅ 1. Config Flow UI Setup

Required: UI-based configuration (no YAML)

class MyConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
    """Handle config flow."""
    
    VERSION = 1
    
    async def async_step_user(self, user_input=None):
        """Handle user step."""
        # Implementation

Files needed:

  • config_flow.py
  • strings.json (UI text)
  • translations/en.json

✅ 2. Automated Tests

Required: Tests for setup and config flow

Minimum tests:

async def test_setup_entry(hass, mock_config_entry):
    """Test setup from config entry."""
    
async def test_unload_entry(hass, mock_config_entry):
    """Test unload config entry."""
    
async def test_config_flow_user_step(hass):
    """Test config flow user step."""

Run: pytest tests/ -v

✅ 3. Coding Standards

Required: Code passes linting

ruff check custom_components/my_integration/
ruff format custom_components/my_integration/

No errors allowed.

✅ 4. Proper Manifest

Required fields in manifest.json:

{
  "domain": "my_integration",
  "name": "My Integration",
  "version": "1.0.0",
  "codeowners": ["@username"],
  "config_flow": true,
  "documentation": "https://...",
  "integration_type": "device|hub|service",
  "iot_class": "local_polling|...",
  "issue_tracker": "https://..."
}

Bronze Checklist

  • Config flow implemented (config_flow.py)
  • async_setup_entry() with tests
  • Ruff linting passes (zero errors)
  • manifest.json properly configured
  • Unique IDs for all entities
  • Basic README.md with setup instructions
  • At least one entity platform

Verification

# Lint check
ruff check .

# Test check
pytest tests/

# Manual check
python scripts/verify_environment.py

Silver Tier (Reliable Integration)

Goal: Handles errors gracefully, provides good user experience.

Requirements

✅ 1. Error Handling

Connection errors → UpdateFailed:

async def _async_update_data(self):
    try:
        return await self.client.async_get_data()
    except ConnectionError as err:
        raise UpdateFailed(f"Connection error: {err}") from err

Authentication errors → ConfigEntryAuthFailed:

except AuthenticationError as err:
    raise ConfigEntryAuthFailed("Invalid credentials") from err

✅ 2. Entity Availability

Entities show unavailable when device offline:

@property
def available(self) -> bool:
    """Return if entity is available."""
    return (
        super().available
        and self._device_id in self.coordinator.data
    )

✅ 3. Coordinator Handles Offline Devices

Graceful degradation:

async def _async_update_data(self):
    try:
        data = await self.client.async_get_data()
        return data
    except UpdateFailed:
        # Log once, don't spam
        if not self._logged_offline:
            _LOGGER.warning("Device offline")
            self._logged_offline = True
        raise

✅ 4. User-Friendly Error Messages

In config flow:

errors = {}
try:
    await validate_input(user_input)
except CannotConnect:
    errors["base"] = "cannot_connect"
except InvalidAuth:
    errors["base"] = "invalid_auth"

In strings.json:

{
  "error": {
    "cannot_connect": "Failed to connect to device",
    "invalid_auth": "Invalid credentials"
  }
}

✅ 5. Troubleshooting Documentation

README.md should include:

  • Common error messages
  • How to resolve connection issues
  • How to debug authentication
  • Where to get logs

Silver Checklist

  • Proper error handling (ConnectionError → UpdateFailed)
  • Authentication failures raise ConfigEntryAuthFailed
  • Entity availability properly managed
  • Coordinator handles offline devices gracefully
  • Troubleshooting documentation in README
  • Log-once patterns for repeated errors
  • Config flow error messages are user-friendly

Gold Tier (Robust Integration)

Goal: Production-ready with comprehensive testing and async architecture.

Requirements

✅ 1. Full Async Codebase

NO blocking I/O:

# ❌ WRONG
def get_data():
    return requests.get(url).json()

# ✅ CORRECT
async def get_data():
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.json()

If no async library exists:

async def sync_operation():
    return await hass.async_add_executor_job(
        blocking_function, arg1, arg2
    )

✅ 2. Test Coverage ≥ 90%

pytest tests/ --cov=custom_components.my_integration --cov-report=html

Open htmlcov/index.html - must show ≥90%

Cover:

  • All config flow steps
  • All error scenarios
  • Setup/unload
  • Coordinator updates
  • All entity platforms
  • Entity availability

✅ 3. Complete Type Annotations

All functions typed:

async def async_setup_entry(
    hass: HomeAssistant,
    entry: ConfigEntry,
) -> bool:
    """Set up from config entry."""

Mypy strict mode passes:

mypy custom_components/my_integration/
# 0 errors

✅ 4. Efficient Data Handling

No redundant polls:

  • Use DataUpdateCoordinator (centralizes updates)
  • Set appropriate update_interval (not too frequent)
  • Use always_update=False if data implements __eq__

Batch operations:

# Fetch all device data in one call
data = await client.async_get_all_devices()

✅ 5. Device Registry Integration

Group entities by device:

@property
def device_info(self) -> DeviceInfo:
    """Return device information."""
    return DeviceInfo(
        identifiers={(DOMAIN, self._device_id)},
        name=self.coordinator.data[self._device_id]["name"],
        manufacturer="Manufacturer",
        model="Model",
        sw_version="1.0.0",
    )

✅ 6. Options Flow

Allow reconfiguration:

async def async_get_options_flow(entry):
    """Get options flow handler."""
    return MyOptionsFlow(entry)

Gold Checklist

  • Full async codebase (no blocking I/O)
  • Test coverage ≥ 90%
  • Complete type annotations (mypy strict passes)
  • Efficient data handling (no redundant polls)
  • Device registry integration
  • All entity platforms have tests
  • Options flow for reconfiguration

Platinum Tier (Excellent Integration)

Goal: Exemplary code quality and maintainability.

Requirements

✅ 1. Code Excellence

Follows all HA style guidelines:

  • Clear, self-documenting code
  • Meaningful variable names
  • Logical code organization
  • No code smells

✅ 2. Documentation

Comprehensive docstrings:

class MyCoordinator(DataUpdateCoordinator):
    """Coordinator for My Integration.
    
    Fetches data from device API every 30 seconds.
    Handles connection errors and authentication failures.
    """
    
    async def _async_update_data(self) -> dict[str, Any]:
        """Fetch data from API endpoint.
        
        Returns:
            Dictionary mapping device IDs to device data.
            
        Raises:
            ConfigEntryAuthFailed: If authentication fails.
            UpdateFailed: If connection fails.
        """

Inline comments for complex logic:

# Calculate exponential backoff: 2^retry * base_delay
delay = (2 ** retry_count) * base_delay

✅ 3. Performance Optimization

Minimal coordinator updates:

  • Only update when data changes
  • Use event-driven updates if possible
  • Implement always_update=False

Memory efficiency:

  • Don't store unnecessary data
  • Clean up resources properly

✅ 4. Active Maintenance

Commitment to:

  • Respond to issues promptly
  • Keep dependencies updated
  • Fix bugs quickly
  • Add features based on feedback

✅ 5. Security Review

No security vulnerabilities:

  • Credentials stored in ConfigEntry.data
  • No credentials in logs
  • Input validation
  • Secure API communication (HTTPS)

✅ 6. Localization

Support multiple languages:

translations/
├── en.json
├── de.json
├── fr.json
└── ...

✅ 7. Diagnostics Integration

Provide diagnostic data:

async def async_get_config_entry_diagnostics(
    hass: HomeAssistant, entry: ConfigEntry
) -> dict:
    """Return diagnostics."""
    return {
        "coordinator_data": coordinator.data,
        "device_info": {...},
    }

Platinum Checklist

  • Code follows all HA style guidelines
  • Clear docstrings and comments
  • Performance optimized (minimal coordinator updates)
  • Active maintenance plan documented
  • Security review completed
  • Localization for multiple languages
  • Integration with HA diagnostics system

Tracking Your Progress

Use the QUALITY_CHECKLIST.md file to track:

## Bronze Tier
- [x] Config flow implemented
- [x] Tests written
- [ ] Linting passes
...

Resources

Tips for Success

  1. Start with Bronze - Don't skip fundamentals
  2. Test as you code - Don't save testing for later
  3. Use the example integration - It meets Gold tier standards
  4. Ask for help - Use Discussions for questions
  5. Iterate - Improve tier by tier, don't rush Platinum

Target: Minimum Bronze, aim for Silver/Gold for best user experience.

Clone this wiki locally