django-micboard
Real-time multi-manufacturer wireless microphone monitoring for Django.
django-micboard is a community-driven, pre-production Django reusable app for monitoring wireless audio systems (Shure, Sennheiser, etc.) in real-time. It provides device discovery, telemetry, alerting, performer assignment, and multi-tenant/multi-location support with a manufacturer-agnostic plugin architecture.
- License: AGPL-3.0-or-later
- Status: Beta (pre-production)
- Maintainer: Single developer (please allow time for issue/PR responses)
- Python: 3.13+
- Django: 5.2 through 6.1
Features
- Multi-Manufacturer Support: Plugin architecture for Shure System API, Sennheiser SSCv2, and more
- Real-Time Updates: Live device telemetry via WebSockets (Channels) or SSE polls
- Device Lifecycle: Automated discovery, registration, tracking, and movement auditing
- Wireless Monitoring: Battery levels, RF signal strength, audio levels, charging status
- Location Management: Buildings, rooms, zones with multi-site/multi-location support
- Performer Assignment: Map performers to devices with activity history
- Alert System: User-specific notification rules for battery, signal, offline events
- Regulatory Compliance: Frequency band coordination and domain auditing
- Multi-Tenant Safe: Optional MSP (Managed Service Provider) mode with organization isolation
- Settings Registry: Typed configuration at each definition's exact declared scope
- Admin Interface: Beautiful Unfold admin theme with advanced filtering and history tracking
Installation
For End Users (Using the App)
Add to your Django project:
uv add "django-micboard[standard,audit]"
Use uv add "django-micboard[standard]" without the optional history app, or
uv add django-micboard when only the core reusable app is needed.
In settings.py:
import os
DEBUG = os.environ.get("DJANGO_DEBUG", "False").lower() == "true"
INSTALLED_APPS = [
# ... Django core apps ...
"micboard",
]
# Optionally, add these for enhanced features
INSTALLED_APPS += [
"django.contrib.sites", # For multi-site support
"unfold", # Modern admin theme
"unfold.contrib.filters", # Unfold date and datetime range filters
"simple_history", # Model change tracking
"huey.contrib.djhuey", # Native Huey Django integration
]
HUEY = {
"huey_class": "huey.RedisHuey",
"name": "micboard",
"connection": {
"url": os.environ.get("REDIS_URL", "redis://localhost:6379/1"),
},
"immediate": DEBUG,
}
# Configure Micboard
MICBOARD_CONFIG = {
"SHURE_API_BASE_URL": os.environ.get(
"MICBOARD_SHURE_API_BASE_URL", "https://localhost:10000"
),
"SHURE_API_SHARED_KEY": os.environ.get("MICBOARD_SHURE_API_SHARED_KEY"),
"SHURE_API_TIMEOUT": int(os.environ.get("MICBOARD_SHURE_API_TIMEOUT", "10")),
"POLL_INTERVAL": 5, # seconds
}
# Exact hostnames allowed for credential-bearing admin API-server checks.
MICBOARD_API_SERVER_ALLOWED_HOSTS = [
host.strip()
for host in os.environ.get("MICBOARD_API_SERVER_ALLOWED_HOSTS", "localhost").split(",")
if host.strip()
]
# Optional: Enable multi-tenancy
MICBOARD_MULTI_SITE_MODE = True
MICBOARD_MSP_ENABLED = False # or True for full MSP mode
MICBOARD_SITE_ISOLATION = "site" # or "organization", "campus"
Micboard intentionally disables generic admin import and export. A host may install the
import-export extra only after defining request-aware resources that validate tenant ownership
for every transferred row and explicitly opting its own admin classes into those resources.
In MSP mode, Django model permissions are necessary but do not override membership roles:
viewer is read-only, operator changes performer assignments through the service-backed
assignment workflow, and admin/owner may mutate rows only in their exact organization and
campus scopes. Host-wide catalogs remain platform-superuser surfaces. Multi-site creation of an
unassigned performer is deliberately disabled until onboarding can bind the performer and first
tenant assignment atomically.
The built-in DisplayWall page renders one typed snapshot for its initial response, periodic HTML
refreshes, JSON consumers, and section fragments. Micboard ships a pinned local HTMX runtime for
offline and restrictive-CSP deployments. The base template still loads Bootstrap from
cdn.jsdelivr.net; hosts that block that origin can override the template with a local asset.
Add to your urls.py:
from django.urls import include, path
urlpatterns = [
path("micboard/", include("micboard.urls", namespace="micboard")),
# ... other patterns ...
]
Run migrations:
uv run --no-sync python manage.py migrate
Host projects should commit their own app migrations and apply django-micboard's shipped
migrations through Django's normal migrate command.
Run the native Huey consumer with:
uv run --no-sync python manage.py run_huey
For Development
CRITICAL: Environment & Dependency Management Policy
This project strictly forbids the use of
pip,pipx,poetry, or Python's built-invenvfor all environment and package management. ALL environments and dependencies must be set up and managed usinguvexclusively. Any documentation, code, or CI which references or suggests non-uvpatterns must be updated or escalated to project maintainers for correction. See CONTRIBUTING.md for full enforcement and escalation procedure.Agents and automation are expected to enforce this pattern in all workflows.
-
Clone the repository:
git clone https://github.com/justprosound/django-micboard.git cd django-micboard
-
Create the uv-managed environment and install every supported extra:
uv sync --locked --all-extras
-
Configure the shell environment (the example project does not load
.envfiles implicitly):export DJANGO_SECRET_KEY="local-development-only" export MICBOARD_SHURE_API_BASE_URL="https://localhost:10000" export MICBOARD_SHURE_API_SHARED_KEY="your-shared-key"
-
Run the example project:
uv run --no-sync python manage.py migrate uv run --no-sync python manage.py createsuperuser uv run --no-sync python manage.py runserver
-
Access the admin:
- http://localhost:8000/admin
- Login with your superuser credentials
Configuration
Environment Variables
The package reads Django settings, not process environment variables directly. The host-settings
example above maps these variables into MICBOARD_CONFIG:
# Shure API
MICBOARD_SHURE_API_BASE_URL=https://shure-api.example.com:10000
MICBOARD_SHURE_API_SHARED_KEY=your-secret-key
MICBOARD_SHURE_API_TIMEOUT=10
# Restrict credential-bearing API server requests to explicit hostnames
MICBOARD_API_SERVER_ALLOWED_HOSTS=localhost,shure-api.example.com
Host projects may choose different variable names; set MICBOARD_CONFIG and the
MICBOARD_* Django feature flags explicitly in their settings module.
Authenticated manufacturer connections require HTTPS or WSS, and certificate verification is
mandatory. For an internal certificate authority, set SSL_CERT_FILE or SSL_CERT_DIR to the
trusted CA bundle before starting Django or Huey.
Using the Configuration API
from micboard.services.settings.settings_service import settings as micboard_settings
# Feature flags
if micboard_settings.msp_enabled:
...
# Get custom settings
timeout = micboard_settings.get("SHURE_API_TIMEOUT", default=10)
# Scoped settings use the same service
value = micboard_settings.get(
"CUSTOM_KEY",
organization=org,
site=site,
default="fallback",
)
See micboard/ARCHITECTURE.md for detailed architecture documentation.
Plugin Architecture
Extend Micboard with manufacturer-specific plugins. Put each plugin in
micboard/integrations/<code>/plugin.py; PluginRegistry discovers it by module and class name.
For example, micboard/integrations/acme/plugin.py can contain:
from typing import Any
from micboard.services.common.base.plugin import ManufacturerPlugin
class AcmePlugin(ManufacturerPlugin):
@property
def name(self) -> str:
return "Acme"
@property
def code(self) -> str:
return "acme"
def get_client(self) -> object:
return object()
def get_devices(self) -> list[dict[str, Any]]:
return []
def get_device(self, device_id: str) -> dict[str, Any] | None:
return None
def get_device_channels(self, device_id: str) -> list[dict[str, Any]]:
return []
def transform_device_data(self, api_data: dict[str, Any]) -> dict[str, Any] | None:
return dict(api_data)
def is_healthy(self) -> bool:
return True
def check_health(self) -> dict[str, Any]:
return {"status": "healthy"}
Load the class or an instance through the registry; no central registration file is required:
from micboard.services.manufacturer.plugin_registry import PluginRegistry
plugin_class = PluginRegistry.get_plugin_class("acme")
plugin = PluginRegistry.get_plugin("acme", manufacturer=manufacturer)
Testing
Run the test suite:
# All tests
uv run --no-sync pytest
# Specific test file
uv run --no-sync pytest tests/test_settings_diff_admin.py -v
# With coverage
just coverage
# Specific markers
uv run --no-sync pytest -m unit
uv run --no-sync pytest -m integration
uv run --no-sync pytest -m django_db
Linting and prek
Use ruff and prek to keep code quality consistent:
uv run --no-sync ruff check .
uv run --no-sync ruff format .
uv run --no-sync prek run --all-files
Release Notes
- Update CHANGELOG.md under [Unreleased] with notable changes.
- A merged
featorfixConventional Commit automatically starts the Prepare Release PR workflow. Run it manually frommainonly for backfills or controlled retries. - Release metadata reaches
mainthrough a protected pull request and required checks. - The publication workflow builds the protected merge commit once, signs Sigstore provenance and SPDX SBOM attestations, verifies the sealed files through TestPyPI, and publishes with environment-bound PEP 740 attestations.
- Stable publication pauses once for production
pypi-releaseenvironment approval. After approval, the workflow publishes to PyPI, creates or verifies the version tag at the exact release commit, and publishes a draft-first GitHub release containing the registry-signed wheel, source archive, SPDX SBOM, publish attestations, and checksums. - If only GitHub release assembly fails after PyPI succeeds, use the audited recovery workflow with the failed run ID, exact commit, and version. It reverifies and reuses the original retained artifact without rebuilding or touching either package registry.
Development Workflow
Agent & Research Workflow Policy
- When you need to search programming documentation, always use the
context7tools (see AGENTS.md Quick Reference).- If you are unsure how to implement or use a library, use
gh_grepto search for up-to-date code examples from GitHub.
-
Install pre-commit hooks:
uv run --no-sync prek install -f --prepare-hooks
-
Run linting/formatting:
uv run --no-sync ruff check . --fix uv run --no-sync ruff format .
-
Type checking:
uv run --no-sync python -m mypy micboard
-
Run tests before committing:
uv run --no-sync pytest uv run --no-sync prek run --all-files
-
Security checks:
uv run --no-sync bandit -r micboard -ll
Important Notes on Migrations
⚠️ CRITICAL: This is a pre-production reusable app, but migration history is protected:
- DO NOT manually edit files in
micboard/migrations/ - DO NOT run
makemigrationscarelessly - ONLY create new migrations when schema changes are approved
- NEVER delete or modify existing migrations
- ALWAYS test migrations thoroughly before production deployment
- USE
uv run --no-sync python manage.py safemigratein production hosts configured withdjango_safemigrate
See CONTRIBUTING.md for details.
Documentation
- Architecture Guide - System design and patterns
- Contributing Guide - Development process
- Changelog - Release notes
- API Documentation - Full reference
Support & Contributing
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Contributing: See CONTRIBUTING.md
License
AGPL-3.0-or-later – This program is free software. See LICENSE for details.
Note: If you use this software in production, you may need to comply with AGPL licensing requirements, including making source code available to users.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_micboard-2026.8.13.1.tar.gz.
File metadata
- Download URL: django_micboard-2026.8.13.1.tar.gz
- Upload date:
- Size: 448.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0844644923e08bd8c5e19e52c13b4005d6c52e51c71f344cadd4bfeb6e169394
|
|
| MD5 |
c06127a404298b367e27655bd9b41a76
|
|
| BLAKE2b-256 |
d7ec35e147e8d5626471736befc6e3e695834ca8518fe0a3a2b2450bef1eaafd
|
File details
Details for the file django_micboard-2026.8.13.1-py3-none-any.whl.
File metadata
- Download URL: django_micboard-2026.8.13.1-py3-none-any.whl
- Upload date:
- Size: 590.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f79d1539e2cc5ca8c26dc049ae30a739c7ad9b8c59d942f3fc330c2973e18c53
|
|
| MD5 |
705d54763c3a08a8015107e4d9ac399c
|
|
| BLAKE2b-256 |
ec59b19f4f1e7a0c1723c2137f2079f1e39dea74a5f97735d7fd0900419c8e83
|