From c1c4bbdd67bccefc5c2aed36aef14688fdd36250 Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Fri, 17 Jul 2026 15:06:46 -0400 Subject: [PATCH 1/9] add dpx crap --- .gitattributes | 2 + .github/AGENTS.md | 679 +++++++++++++++++++ .github/ISSUE_TEMPLATE/bug-report---.md | 22 + .github/ISSUE_TEMPLATE/feature-request---.md | 17 + .github/PULL_REQUEST_TEMPLATE.md | 26 + .gitignore | 34 + CHANGELOG.md | 59 ++ Gemfile | 4 + VERSION | 1 + _config.yml | 10 + dpx_release_note_template.md | 24 + images/dubpixel_identicon.png | Bin 0 -> 5532 bytes images/front.png | Bin 0 -> 5213 bytes images/front_render.png | Bin 0 -> 5146 bytes images/logo.png | Bin 0 -> 22406 bytes images/logo_HF.png | Bin 0 -> 5057 bytes images/pcb_front.png | Bin 0 -> 5196 bytes images/pcb_rear.png | Bin 0 -> 5099 bytes images/rear.png | Bin 0 -> 5090 bytes images/rear_render.png | Bin 0 -> 5024 bytes readme.md | 349 +++++++--- 21 files changed, 1124 insertions(+), 103 deletions(-) create mode 100644 .gitattributes create mode 100644 .github/AGENTS.md create mode 100644 .github/ISSUE_TEMPLATE/bug-report---.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request---.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 Gemfile create mode 100644 VERSION create mode 100644 _config.yml create mode 100644 dpx_release_note_template.md create mode 100644 images/dubpixel_identicon.png create mode 100644 images/front.png create mode 100644 images/front_render.png create mode 100644 images/logo.png create mode 100644 images/logo_HF.png create mode 100644 images/pcb_front.png create mode 100644 images/pcb_rear.png create mode 100644 images/rear.png create mode 100644 images/rear_render.png diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..dfe0770424 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.github/AGENTS.md b/.github/AGENTS.md new file mode 100644 index 0000000000..4e00133ad5 --- /dev/null +++ b/.github/AGENTS.md @@ -0,0 +1,679 @@ +# dpx Agent Workflow & Documentation Standards - v1d6 + +This document provides operational directives for AI coding assistants (GitHub Copilot, Claude Code, Cursor, etc.) working on dubpixel projects. These rules ensure consistent workflow automation, code quality, and documentation maintenance across all repositories. + +--- + +## PROJECT: [Project Name] + +**Instructions for customizing this section:** +Replace the placeholders below with your project's specific information. Remove subsections that don't apply. This template is intentionally verbose — prune what you don't need. + +**Status:** [e.g., v0.1.0 complete (2026-06-05) ✅] +**Branch:** [e.g., `feature/core-app-implementation`] +**Version File:** [e.g., `VERSION` (currently 0.1.0)] + +### Architecture (2-minute summary) + +[One-paragraph overview: what this project does, core tech, how it works] + +**Example:** "Browser-based monitoring tool for Phabrix QX waveform monitors. Pure vanilla JS (no frameworks, no build step, no CDN). Connects to QX REST API on port 8080, polls status/logs every 2-5s, stores settings in localStorage. Works offline in airgapped broadcast facilities." + +| Component | Tech/Location | Purpose | Notes | +|-----------|---------------|---------|-------| +| [Component 1] | [Tech] / `path/` | [What it does] | [Key details] | +| [Component 2] | [Tech] / `path/` | [What it does] | [Key details] | +| [Component 3] | [Tech] / `path/` | [What it does] | [Key details] | +| [Reference docs] | [Format] / `path/` | [What it is] | **Source of truth for [topic]** | + +### Agent Rules (for this repo) + +**Before ANY code change:** +1. Work from `[main/master]` branch; create feature branch: `feature/brief-description` +2. Bump VERSION file per semantic versioning (AGENTS.md §1) +3. Create git commit for version bump, tag it: `git tag vX.Y.Z` + +**While coding:** +- [Project-specific rule or constraint] +- [Technology requirement or restriction] +- [Testing/validation requirement] +- Keep changes small, test before committing +- File header per AGENTS.md §3 + +**When done:** +- Update CHANGELOG.md with feature list +- Create PR per AGENTS.md §1 template +- [Any project-specific verification steps] + +### Critical Constraints + +**MUST HAVE:** +- ✅ [Required capability or dependency] +- ✅ [Required technology or approach] +- ✅ [Required compatibility or standard] + +**DO NOT:** +- ❌ [Forbidden action or technology] +- ❌ [Assumption that must be avoided] +- ❌ [Hard-coded value or static configuration] +- ❌ [Change that requires explicit verification] + +### Key Decisions + +- **[Decision Title]:** [Explanation - why this approach was chosen over alternatives] +- **[Decision Title]:** [Rationale for architecture/design choice] +- **[Decision Title]:** [Context for future agents] + +**Examples:** +- **Dual README templates:** Hardware needs schematics/BOMs, software needs API docs - fundamentally different documentation needs +- **No WebSocket:** QX REST API is HTTP-only. Polling is the only option. +- **Bootstrap on connect:** Device specs vary by boot mode - auto-detect on initial connection + +### Gotchas & Landmines + +1. **[Issue Title]:** [Description]. [Workaround or solution]. [Where to look for more info] +2. **[Issue Title]:** [Description]. [Workaround or solution]. +3. **[Issue Title]:** [Description]. [Always check/verify X before doing Y]. + +**Examples:** +- **CORS issue:** API calls from `file://` origin fail. Use launch script or Python server, not direct open. +- **Boot modes matter:** Device can boot in different modes. Different endpoints available per mode. Always auto-detect on connect. +- **Manual is authority:** If specs seem odd, check `/docs/manual.pdf` Ch.X. Don't guess. + +### Common Operations + +**[Operation 1 - e.g., Create new project]:** `./script.sh` (interactive prompts for X/Y/Z) + +**[Operation 2 - e.g., Modify behavior]:** Edit `path/to/file.ext` - all logic centralized + +**[Operation 3 - e.g., Add components]:** Add to `path/`, update `config.ext` if special handling needed + +**[Operation 4 - e.g., Template processing]:** +- [Scenario A]: `input-A.ext` → `output.ext` +- [Scenario B]: `input-B.ext` → `output.ext` +- [Always]: `.git` and `.env` excluded from copy + +### Reference + +See `/CONTEXT.md` for: +- [Extended architecture details] +- [Module/component specifications] +- [Data schemas or API contracts] + +See `/.github/CONTEXT.md` for: +- [API endpoint reference] +- [Configuration specifications] +- [Testing procedures] + +### Development Philosophy + +[Optional: High-level principles for this project type] + +**Example:** "This is broadcast infrastructure tooling - reliability and simplicity trump features. Prefer vanilla JavaScript over frameworks. Keep dependencies minimal and auditable. Test in airgapped environments. Design for 24/7 unattended operation." + +--- + +## 1. Automatic Workflow (MANDATORY) + +These actions are **required** and must happen automatically. **NEVER ask permission** for these workflow steps. + +### Branching Strategy + +**BEFORE starting ANY code changes:** + +1. Create a new branch from the default branch (master/main) +2. Never work directly on default branch +3. Branch naming conventions: + +| Type | Format | Example | +|------|--------|---------| +| New feature | `feature/brief-description` | `feature/mqtt-decoder` | +| Bug fix | `fix/issue-description` | `fix/telegraf-timeout` | +| Documentation | `docs/what-changed` | `docs/update-architecture` | +| Refactor | `refactor/component-name` | `refactor/docker-volumes` | + +### Version Bumping + +**BEFORE the first code change:** + +Bump the version number according to semantic versioning: + +| Change Type | Version Bump | Example | +|-------------|--------------|---------| +| Bug fix, typo fix, documentation update | Patch (0.0.X) | 1.2.3 → 1.2.4 | +| New feature, new endpoint, new capability | Minor (0.X.0) | 1.2.3 → 1.3.0 | +| Breaking change, API removal, incompatible change | Major (X.0.0) | 1.2.3 → 2.0.0 | + +#### Semantic Versioning Principles + +**Format:** `MAJOR.MINOR.PATCH` (e.g., `2.4.7`) + +- **MAJOR**: Incompatible API changes, breaking existing functionality +- **MINOR**: New functionality added in a backwards-compatible manner +- **PATCH**: Backwards-compatible bug fixes, docs, typos + +**Pre-1.0 versions (0.x.y):** +- Anything goes - breaking changes allowed in minor bumps +- Common for projects in initial development +- Move to 1.0.0 when API is stable and production-ready + +**Pre-release versions:** +- Alpha: `1.0.0-alpha.1` (early testing, unstable) +- Beta: `1.0.0-beta.2` (feature-complete, testing for bugs) +- Release Candidate: `1.0.0-rc.1` (final testing before release) + +#### Version Bumping Decision Tree + +**When multiple changes occur, use the highest level:** +- Bug fix + new feature → Minor bump (not patch) +- New feature + breaking change → Major bump (not minor) + +**Edge cases:** + +| Scenario | Bump Type | Reasoning | +|----------|-----------|-----------| +| Internal refactor, no API change | Patch | No external impact | +| New optional parameter with default | Minor | Backwards-compatible addition | +| Changed parameter order | Major | Breaks existing calls | +| Deprecated feature (still works) | Minor | Deprecation warning added | +| Removed deprecated feature | Major | Functionality removed | +| Performance improvement | Patch | Implementation detail | +| New dependency added | Minor | Expands capabilities | +| Security fix | Patch | Even if behavior changes slightly | +| Database schema change | Major | Requires migration | +| Config file format change | Major | Breaking existing configs | + +#### Version Bump Workflow + +1. **Determine bump type** based on changes planned +2. **Update version number** in code/config files +3. **Create git commit**: `bump version to X.Y.Z` +4. **Tag the commit**: `git tag vX.Y.Z` (note the `v` prefix) +5. **Push with tags**: `git push && git push --tags` +6. **Update CHANGELOG** (if present) with version and changes +7. **Proceed with feature/fix implementation** + +**Version commit should be standalone** - don't mix version bump with other changes. + +#### Changelog Integration + +If project has CHANGELOG.md, update it with version bump: + +```markdown +## [1.2.0] - 2026-02-13 + +### Added +- New feature description + +### Fixed +- Bug fix description + +### Changed +- Breaking change description +``` +**If no CHANGELOG.MD file exists:** Create one in the root of the project. + +**Where to bump version:** +- Python: `__version__` in `__init__.py` or `pyproject.toml` +- Node.js: `version` field in `package.json` +- General: `VERSION` file or constant in main entry point +- Docker: Version tag in `docker-compose.yml` or `Dockerfile` labels + +**If no version file exists:** Create one in an appropriate location for the project. + +### Version File Standards & Location + +To ensure consistent version identification across projects, follow these standards: + +#### Python Projects + +**Preferred location: `app/__init__.py` or `src/__init__.py`** + +```python +"""Project description.""" + +__version__ = "1.0.0" +__author__ = "dubpixel" +``` + +**Alternative: `pyproject.toml` (for modern Python packaging)** + +```toml +[project] +name = "project-name" +version = "1.0.0" +``` + +**Alternative: `VERSION` file in project root** + +``` +1.0.0 +``` + +Then read it in your module: +```python +from pathlib import Path +__version__ = (Path(__file__).parent / "VERSION").read_text().strip() +``` + +#### Node.js/JavaScript Projects + +**Location: `package.json`** (standard) + +```json +{ + "name": "project-name", + "version": "1.0.0", + "description": "Project description" +} +``` + +#### Docker Projects + +**Location: `docker-compose.yml` labels AND `Dockerfile`** + +`docker-compose.yml`: +```yaml +services: + app: + build: . + labels: + - "org.opencontainers.image.version=1.0.0" + - "org.opencontainers.image.created=${BUILD_DATE}" +``` + +`Dockerfile`: +```dockerfile +LABEL org.opencontainers.image.version="1.0.0" +LABEL org.opencontainers.image.title="Project Name" +``` + +#### Bash Scripts/Utilities + +**Location: Top of main script or separate `VERSION` file** + +```bash +#!/bin/bash +VERSION="1.0.0" +SCRIPT_NAME="manage.sh" + +# Or read from VERSION file: +# VERSION=$(cat VERSION) +``` + +#### Version Display (REQUIRED) + +**Always provide a way to display the version:** + +- Python CLI: `python -m myapp --version` +- Node.js: `npm run version` or built into CLI +- Docker: `docker inspect | grep version` +- Bash: `./script.sh --version` + +**Example implementations:** + +```python +# In your main.py or CLI entry point +import argparse +from app import __version__ + +parser = argparse.ArgumentParser() +parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}') +``` + +```bash +# In bash script +if [[ "$1" == "--version" ]] || [[ "$1" == "-v" ]]; then + echo "$SCRIPT_NAME version $VERSION" + exit 0 +fi +``` + +#### Multi-Component Projects + +For projects with multiple components (e.g., frontend + backend + Docker): + +1. **Synchronized versioning**: All components share the same version +2. **Central `VERSION` file** in project root +3. **Scripts/tools read from central file** + +Example structure: +``` +project-root/ +├── VERSION # 1.0.0 +├── backend/ +│ └── __init__.py # Reads ../VERSION +├── frontend/ +│ └── package.json # Reads ../VERSION via build script +└── docker-compose.yml # Reads VERSION via envsubst or build args +``` + +### Pull Request Creation + +**AFTER completing the task:** + +Create a pull request with this format: + +```markdown +## Changes +- [Brief list of what changed] +- [One item per significant change] + +## Testing +- [How to verify the changes work] +- [Commands to run or steps to follow] + +## User Prompt +[The original request from the user - verbatim] +``` + +**PR Title Format:** `[Component] Brief description` + +Examples: +- `[MQTT] Add BLE decoder support` +- `[Docs] Consolidate architecture documentation` +- `[Telegraf] Fix enum processor deprecation` + +**NEVER ask permission to create the PR - just do it.** + +--- + +## 2. Progress Tracking for Multi-Step Work + +When working on tasks that span **more than 3 files** OR **more than 30 minutes of work**: + +### Checkpoint Progress + +Provide a status update using this template: + +```markdown +## Progress Checkpoint + +✅ **Completed:** +- Item 1 description +- Item 2 description + +⬜ **Remaining:** +- Item 3 description +- Item 4 description + +→ **Next Action:** [Specific next step you will take] +``` + +### When to Checkpoint + +- After completing a logical phase of work +- Before switching to a different component +- When encountering a blocker or decision point +- Every 3-5 file edits in large refactors + +### Resuming from Checkpoint + +When continuing work after a checkpoint: +1. Read the last checkpoint status +2. Start with the "Next Action" item +3. Update checkpoint when that phase completes + +**Purpose:** Prevents agents from getting lost in complex multi-step tasks and provides visibility to the user. + +--- + +## 3. File Header Standards + +All code files must include a comprehensive header comment section: + +``` +# ================================================================================ +# [FILE TYPE] - [FILE PURPOSE] +# ================================================================================ +# you can maybe write some stuff here - tagline etc. +# ================================================================================ +# PROJECT: [project_name] +# ================================================================================ +# +# File: [filename] +# Purpose: [what this file does] +# Dependencies: [key dependencies if any] +# +# CHANGE LOG: (if needed but should really be in the changelog for the git) +# +# 2026-03-06: Complete rewrite - Interactive wizard (v2.1.0) +# +# ================================================================================ +``` + +### Header Guidelines + +- Use consistent separator lines (80 characters of `=`) +- Adjust comment syntax for the language (`#` for Python/bash, `//` for JS/C++, etc.) + + +--- + +## 4. Documentation Standards + +### Project Context Documentation + +Project-specific architecture, decisions, and operational knowledge should live in the **PROJECT section at the top of this file**. This keeps rules and context unified in one scannable document. + +**When to use a separate CONTEXT.md:** +Only create a separate `CONTEXT.md` if reference data becomes large enough to be noisy: +- Long IP/VLAN tables +- Full API response examples +- Hardware pinout references +- Extensive data schemas + +If you create CONTEXT.md for overflow, add a reference in the PROJECT section at the top: "See CONTEXT.md for full network topology." + +### How to Document Project Context + +**DO:** +- ✅ Keep it clean, factual, and scannable +- ✅ Update when architecture changes +- ✅ Add information when you learn important project details +- ✅ Use tables, code blocks, and clear headings +- ✅ Think: "What does the next agent need to know?" +- ✅ Write in present tense, authoritative voice + +**DON'T:** +- ❌ Append conversation transcripts +- ❌ Include timestamps like "On Feb 12 we discussed..." +- ❌ Make it a session log or diary +- ❌ Duplicate content from README.md (link instead) +- ❌ Let it become verbose or messy + +**Update frequency:** Whenever you make architectural changes or learn critical project information. + +--- + +## 5. Core Principles + + +### No Modifications to Working Code + +- Do not refactor, optimize, or "improve" code that is working unless explicitly requested +- Avoid drive-by refactors when implementing a feature +- If you see potential improvements, mention them but don't implement without approval + +### Comprehensive Commenting + +- Document all code with clear, meaningful comments +- Preserve existing comments unless they become obsolete +- Remove or update comments that are no longer accurate +- Document WHY, not just WHAT (the code shows what, comments explain why) + +### Small, Incremental Changes + +- Make one logical change per commit +- Break large tasks into smaller steps +- Test each change before moving to the next +- Make it easy to review and roll back if needed + +### Stay Focused + +- Complete the current task before suggesting next steps +- Answer only what is asked +- Don't anticipate or propose additional work unless requested + +### Document Everything + +- README.md must be updated and maintaned when appropriate as per these guidelines +- CONTEXT.md must be updated and maintaned when appropriate as per these guidelines +- a comprehensive CHANGELOG.md must be kept updated and maintaned when appropriate as per these guidelines +- you can maintain a small changelog in the header if you wish but main changelog should be in the MD + +--- + +## 6. Documentation Standards + +### Inline Documentation + +- Maintain comprehensive inline documentation +- Update comments when code changes (keep them in sync) +- Document all function parameters and return values +- Include usage examples for complex functions +- Explain algorithms and business logic + + +### README Files + +- Keep README.md current and accurate +- README is user-facing - focus on how to USE the project +- **Confirm all changes to README with the user before committing** +- README should not duplicate CONTEXT.md (different audiences) + +### CHANGELOG.MD + +- Keep CHANGELOG.md current and accurate +- CHANGELOG is user-facing - focus on changes, version numbers, dates and git hashes if needed +- **keep this automated in background** +- changelog could be retroactively updated to reflect git commit names if that adds clariy +- **any changes to existing changelog line items should be confirmed with user** + +### Markdown Style + +- Use consistent heading hierarchy (don't skip levels) +- Use tables for structured information +- Include code blocks with language tags +- Use relative links to other project files +- Keep line length reasonable (~80-100 chars for prose) + +--- + +## 7. Code Quality Guidelines + +### General Principles + +- Write clear, readable code with meaningful names +- Follow established coding patterns within the project +- Implement proper error handling (don't use bare `except:` or `catch`) +- Write testable code with clear interfaces +- Maintain consistent formatting and style + +### Language-Specific + +Agents should infer and follow the conventions of the language they're working in: +- Python: Follow PEP 8 +- JavaScript: Follow project's ESLint config if present +- Bash: Follow Google Shell Style Guide principles +- Other languages: Use community-standard style guides + +### Testing + +- Add tests alongside new logic when appropriate +- Use deterministic inputs for tests (inject time/randomness, don't read system state) +- Name tests by behavior (e.g., `test_early_finish_extends_break`) +- Include both positive and negative test cases +- if the process includes: using ssh into a remote server, or user input in any way. open a terminal first for the user so you both can read it. + +--- + +## 8. Change Management + +### Commit Practices + +- **Commit message format:** Short, plain English, lowercase verb + - Examples: `add mqtt decoder`, `fix telegraf config`, `update documentation` +- Make one logical change per commit +- Commit functional units (don't commit broken code) + +### Before Committing + +- Verify the code works (run/test it) +- Update all relevant documentation +- Update file change logs +- Remove debug code and console.log/print statements +- Check that no credentials or secrets are included + +### After Committing + +- Push to the feature branch +- Create PR (as described in Section 1) +- Include verification steps in PR description + +--- + +## 9. Collaboration Standards + +### Respect Existing Architecture + +- Understand existing architectural decisions before changing them +- Ask for clarification when requirements are ambiguous +- Suggest alternatives when appropriate, but don't insist +- Consider the impact of changes on the broader codebase + +### Maintain Backwards Compatibility + +- Don't break existing APIs unless explicitly requested +- Provide migration paths for breaking changes +- Document any compatibility changes in PR description + +### Communication + +- Explain the reasoning behind suggested changes +- Provide rollback information when making significant changes +- Be transparent about limitations or uncertainties +- Keep responses concise and focused + +--- + +## 10. Configuration & Secrets + +### Environment Variables + +- Use `.env` files for local development +- Provide `.env.example` with all required variables (use placeholder values) +- **NEVER commit** `.env` files or actual credentials to git +- Document all environment variables in CONTEXT.md or README.md + +### Sensitive Data + +- Keep credentials in environment variables, not hardcoded +- Use service account files in standard locations (e.g., `~/.config/gcloud/`) +- Add sensitive files to `.gitignore` immediately +- If secrets are accidentally committed, notify the user immediately + +--- + +## Summary: Agent Checklist + +Before starting work: +- [ ] Create feature branch +- [ ] Bump version appropriately + +While working: +- [ ] Follow file header standards +- [ ] Update change logs in modified files +- [ ] Keep changes small and focused +- [ ] Checkpoint progress if task is large +- [ ] Update PROJECT section if architecture changes + +After completing work: +- [ ] Test/verify the changes +- [ ] Update relevant documentation +- [ ] Create PR with proper format +- [ ] No credentials committed + +--- + +*These standards ensure consistent, high-quality AI assistance across all Dubpixel projects.* diff --git a/.github/ISSUE_TEMPLATE/bug-report---.md b/.github/ISSUE_TEMPLATE/bug-report---.md new file mode 100644 index 0000000000..1398711665 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report---.md @@ -0,0 +1,22 @@ +--- +name: "Bug report \U0001F41E" +about: Create a bug report +labels: bug + +--- + +## Describe the bug +* A clear and concise description of what the bug is. + +### Steps to reproduce +* Steps to reproduce the behavior. + +### Expected behavior +* A clear and concise description of what you expected to happen. + +### Environment + - OS: [e.g. Arch Linux] + - Other details that you think may affect. + +### Additional context +* Add any other context about the problem here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature-request---.md b/.github/ISSUE_TEMPLATE/feature-request---.md new file mode 100644 index 0000000000..ea98d963a7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request---.md @@ -0,0 +1,17 @@ +--- +name: "Feature request \U0001F680" +about: Suggest an idea +labels: enhancement + +--- + +## Summary +* Brief explanation of the feature. + +### Basic example +* Include a basic example or links here. Photos and diagrams are great! + +### Motivation +* _Why are we doing this?_ +* _What use cases does it support?_ +* _What is the expected outcome?_ \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..acc0efd6f9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +## What does this PR do? + + + +## Why? + + + + +## How was it tested? + + + +## Screenshots / recordings + + + +## Anything to call out? + + + +## Checklist + +- [ ] Tested locally +- [ ] No debug/temp code left in +- [ ] Docs updated if needed \ No newline at end of file diff --git a/.gitignore b/.gitignore index a2f10883a6..bb9ea9c796 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,37 @@ wled-update.sh /wled00/wled00.ino.cpp /wled00/html_*.h /wled00/js_*.h +### DPX KICAD GIT IGNORE v0.5.4 +# Generic backup files +*~ +\#* +.\#* +# Any dir that ends in -old or some that start wit zz +**/*_old/** +**/zz_reference/** +**/ZZ_IGNORE/** +**/zz_archive/** +# other stuff +**/.DS_Store +*.gsheet +##########------ KICAD SPECIFIC STUFF ------###### +# KiCad backup files +*.bak +*.bck +*.kicad_pcb-bak +**/*.kicad_pcb-bak +**/*-backups/*.zip +**/*-backups/** +*-backups/** +**/template-inspiration/** +# KiCad generated files +*.erc +*.net +*-cache.lib +*-rescue.lib +*.lck +# all the footprints cache +fp-info-cache +*/fp-info-cache +# kicad local profile +*.kicad_prl diff --git a/CHANGELOG.md b/CHANGELOG.md index f591fc2b2c..971c61c074 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1626,3 +1626,62 @@ - Created changelog.md - make tracking changes to code easier - Merged pull request #766 by @pille: Fix E1.31 out-of sequence detection +# Changelog +All notable changes to this project will be documented in this file. +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Added +- +### Changed +- +### Deprecated +- +### Removed +- +### Fixed +- +### Security +- +--- +## [0.1.0] - YYYY-MM-DD +- Initial release +- Core functionality implementation +--- +## Version Guidelines +### Semantic Versioning (MAJOR.MINOR.PATCH) +- **MAJOR**: Breaking changes, incompatible API modifications +- **MINOR**: New features, backwards-compatible additions +- **PATCH**: Bug fixes, documentation updates, typos +### Change Categories +- **Added**: New features or capabilities +- **Changed**: Changes to existing functionality +- **Deprecated**: Features marked for future removal (still working) +- **Removed**: Removed features or functionality +- **Fixed**: Bug fixes +- **Security**: Security patches or vulnerability fixes +### Example Entry Format +```markdown +## [1.2.0] - 2026-03-15 +- New authentication system with JWT tokens +- Export functionality for CSV and JSON formats +- Dark mode toggle in user preferences +- Improved database query performance by 40% +- Updated UI library from v2.1 to v3.0 +- Fixed memory leak in background worker process +- Corrected timezone handling in date picker component +- Patched XSS vulnerability in user input validation +``` +### Version Comparison Links +Add these at the bottom of the file (replace with your repo owner/name): +[Unreleased]: https://github.com/owner/repo/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/owner/repo/releases/tag/v0.1.0 +--- +## Tips for Maintaining This Changelog +1. **Update as you work**: Add entries when making changes, not at release time +2. **Keep it scannable**: Use clear, concise descriptions +3. **Link to issues/PRs**: Include `(#123)` references when relevant +4. **Date format**: Use ISO 8601 (YYYY-MM-DD) +5. **Group by type**: Keep all Added items together, all Fixed items together, etc. +6. **User perspective**: Write what changed for users, not implementation details +7. **Unreleased section**: Keep active changes here, move to version section on release diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..e9931dedbf --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source "https://rubygems.org" + +gem "github-pages", group: :jekyll_plugins +gem "jekyll-commonmark-ghpages" # This should work without needing a local build diff --git a/VERSION b/VERSION new file mode 100644 index 0000000000..6e8bf73aa5 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000000..17f43ffb2c --- /dev/null +++ b/_config.yml @@ -0,0 +1,10 @@ +title: dpx_readme_template +description: a readme template +remote_theme: pages-themes/midnight@v0.2.0 +plugins: +- jekyll-remote-theme # add this line to the plugins list if you already have one +theme: jekyll-theme-minimal +markdown: kramdown +kramdown: + parse_block_html: true + diff --git a/dpx_release_note_template.md b/dpx_release_note_template.md new file mode 100644 index 0000000000..d85149a706 --- /dev/null +++ b/dpx_release_note_template.md @@ -0,0 +1,24 @@ + +--- +## [1.0.0](https://github.com/dubpixel/projectname/compare/1.0.0...1.0.0. ) (releasedate) + +> Description + +### Upgrade Steps +* [ACTION REQUIRED] +* + +### Breaking Changes +* + +### New Features +* + +### Bug Fixes +* + +### Performance Improvements +* + +### Other Changes + diff --git a/images/dubpixel_identicon.png b/images/dubpixel_identicon.png new file mode 100644 index 0000000000000000000000000000000000000000..b2309a8520d565c97ae31594b2e4cc1551a6315d GIT binary patch literal 5532 zcmeAS@N?(olHy`uVBq!ia0y~yU|a&i985rwk9xkt-{E3=p2uL!UiXY8*4K*dkZNjyg9=#Dm@x3BQ!ZEh?o8U{W`y%g+t)S zdIz=a*0~&N4i7doY_Pu5@PD6uoub16XNMb{)=Vs692~nvbKg~{zx8~e$C#-8hC?7i zQQ=M4mY?gyBet?wv9!$HpzM&)+OQ$|;OX2?>-P>SJgWWjd7SI{ST9W2pD2 zVWVM2Y0}syRyOmuivPN88Np8fbSPjc4{&EvM# zTpcfK-zX%8=Vu(3k-xwBoMF+^!t;GhZeH;LQ#PzNUzyz3|331$#LiDU(%l)Am+EVH z-MBjYisA9&-`5oP#8lqdytrZFC2IxY z=Ho}(*D}iCa^K%*BrN&D>dLvhYBJafrF|2%`+-g~2>R8us3mrz+~gbKA?IH`!8lpmI#p_YRUE6) z=MU<|Xa4(F?p-3kob$*t#o`MlabNdvrL;NT`1${_vx0Hi#^5-6U3)*_6K9$?RM)(^ z+@=ukpY|qc`4h&u5dt7V;WGZlGdGUt~DeKRF<&#OvN zWM!3qxBRj2RWRm1^zP$If9a+g+nF1?=T2fTNpb`U`rWW)F#@`8>4%4rlf;9+vFS9`W@N0|WiR+Ukci+&gbWj%q3%1;agb0`X zJk?65rStMXZxKcgQD6p#DjN;B(SQRd^U)Ls%+bR>t2*nwG5TJ}#mK}G$J%mNyIY=9 z;K!_n4Zow@@3u2EhBGF9KlR9+iDjRf!kc~90>3LdJP38Tv3Jvti42YFIXQN(FTGOB yAy6SIP_|yDPQ~FtHq)VZ*|MebBiFbC`zNr?J}RCXFbg>9%HZkh=d#Wzp$PzrProt% literal 0 HcmV?d00001 diff --git a/images/front.png b/images/front.png new file mode 100644 index 0000000000000000000000000000000000000000..1b07d3c8b753c47637413aad9d7a400f7a35ec54 GIT binary patch literal 5213 zcmeHKc~nzZ9=;)9C`dr9EGhxDZo?|tx`Y@P5SLadSeBs}8APlgM8brWC?tUnE?CA2 z!B)T}DaF zenxPs_uk*?llC5R7vNNLdQspqLy85!0vSgirX^D2yCQu2#z)65%#=@I`nO#wA&Dbj-C5S`&%Z8;tbDOE-v87Bs z6z)%w2}R7F-_4|)!D;4>)sr`~ahe7CH-2c>%Un=&;m%qr;dP-Dd+CwRr6Dh)uREYM zLC)cg3beecB|3 zkH+#;Z9Nkv5CbxZs0NzMsUiF06Y^AS?PPVlI<0-dVP*8)4msJLSaWApBz%YBg0w|V zQG8;cC;Z!yEx|O7iD?`%k7FhbjJq9layDR{1ZZFD`@@yl! z?G98u&1sssa)@~+K`xNUuAD)fQJckCx~uY1_bjN+l`On>AylG;*qQN>?V@`=sWdh+ zjb;-Nked{In5T+NR0ak>HJZ9+D7-#3#P&EKC@Q!3_goS^T%1R&`Qw;Qwx!9qsWbiz z8$9uRRu#Z)t72 z-c0OFV`b@zVHAABi*l?w1Mh^k^e7|<3kix4Q3Fc>C2y?V?e6(RE64O|MXSq zucvrr$<4q`pNxP}Z=T}X+O-(yL;F>hZuE&wYuI+%HO6&!UeoUMr)$p>zqk4giFId7 zN`wQ@Wg=mCq2*{_kby04Lq5I}6CAA9SLIt{`4QEbZB-**_uJmX@B}YIPo*6Ad|Z}w zhI{-Z9^wW72ls-ub?RDqaKz<&DfWTin7QNbH-#UT>BSuFRWiQc?RI(grsidBfTaPi8Dc2fpHM$4EA;-Se`W%U!?~HA=FTBqp>vn< z%g>jFT|Ys75nC(FE(+RSw^d!6JtJ>*h-6#74MCslQsf+Zz-{kyi zHOxVJ=jq~ZOh?*~YlCc6jM6Q6{4aJ`jB^mbuRQIR1?hyKD1*EIzBJ^ZKwaLxnL~>x{_BW)VcT3UBrbe3~+{F z@40>ND*ZA^Fba{b8Jg!JP4h*Q^q!Bt@ugvm89lvsY8c;jUzQS=7)jTLSF1x<`1Ga_ z_s5&ohhkxb?sC#v^_kiZ%|_V6>Ke33yYmC%1x3MLh0b3p9Hxs;^p&k8Yh(_0_2-1} zeZrK%IBqrF!x%$qvlr?IqtRs8H)P7+5U!UCl;QRFnZ~`n|15uoW%5I z%$!eJ>=5mAtEsxKyc3nLRV#EoNOemLc8+O$G=rzL17a4Hl!9xFbv zHsWTkSiDv)sMYqRvByjtMoa|N`{Dm11~!+Zqe!fSYhD(P>f0Hx(|?a&+13NB{{lms BPoDq) literal 0 HcmV?d00001 diff --git a/images/front_render.png b/images/front_render.png new file mode 100644 index 0000000000000000000000000000000000000000..d38fbec63bb7243f918184deb5a8426a622a53bc GIT binary patch literal 5146 zcmeHKYgCfi8s3J8rHQ7kv=q9TwIZ{uNh8v!)Jh}sbn~F;S!HCHQeH<45mv{U^hiyf zG_%Yh$J3aack}vLIhD?6pj{+KlqLll(a!!5n&wZO|EIkcOa1oe=6Rp@d7t;) z-}qB~X3v^G3ji>C$M$Uj0AOV3$8-jKa;If$1^h9Sxjir%05fa!V+3+?Z2_?UX~(uN z_a@}Zd%yg4VEY`b|Gl%clW~!)8G(B*kNeSfhvh$b@msq@RQT}Zfu(u=$V>FR&+9V- z{{sV_=T`*-`#Zl)`DM8Xm9+)FU)!-qu|6IRZ%9`>3u-)WA zZ#)6H929#a9facKw6$HpL- zvqSsvPSKDv;@o81;#S%HwTaSo#_<3wUs#J-ziCZs_{~Ih6qlSth2OgbS6{`yDi-=g zJ-wT6Is$;dr;biu!YlH{$NaD{(V}_=K!|`1cEI@20|V-A~=3O~`tRPmk@V z7yu0Hk&Dh?bAN2INof-$vZbiBJ#MtT+fzVX$(C3QzDmtwLdXCl?P3mUA{zb`217Z0 zQ68sWq+>E=Yeg&$G@FhnDumI6THFMVK%e7>JuZ;>`)mIob>>J1^?(gw0-VDrkGsDT z=e?feEh5zXQt(`WZ&LQBv-eb|$i+N-?e}KDZEpYJo65)cJ(M71j!skVJsaC{lBoZ* z5#Xr1{~|!nEoG_l4jn>}c&lxTPLDM$0&{irM{lXlDA!y!&!dka#%NrhT5pMCMIM_Edan8$Eyj| z8OvW@e-tS%>XYSXpid30`zXwPr4z0+L|GeVw$PD18ipO!^k3n>-Hi`GK>|+c%xP(* zIuh*oFDp#|aoGo*LvS(CK}L%;*MBg3_+SYHkNmegVtUr6}I>P_(R zarFb^3%b1Fq|r(4Mute1I?(C>C-9Jpt{4(MzgQQeJQMO=>10-!0N2#MJ{bPHVttE) zG|;Amn=N%5ri2*al1Ls~l$_l@0XY$m%vqTB1J=X=YMQGQ62M zw{`vDHOg-HW5ycZ$5O;-GM>+>4|hORIuEb_n!imPVD)Dj$8(;~xf;iay2A4|01F^5 zPu&ixjxhor1F^~9`!0JXFD@g(t%$0G_HW(S)!_b z?3hl58<*G}Gy)^yI( z4UGOjHaQ@EP%_A~j+5Qo+SyxVapKu+Tizj6xu+GUdT{;dH+ zi7%7xkM+ap}JMzkH ze5>#s=Xv7vs{!84TU4Kp1^_DEcOF92&U$B0@M%L&dRnj{>eX_Ud?zNA&)%cyce}8UraUpKK`mp^RKC?I zE5!`r>4qti8QqJe8Vc&dGW{J3uzlRkxPydDJx02&?&W6P0Z|kRA3$nZyj(Z zm5<+rL*Pd@CM2dw0z-l6=(O&AH&1`eVD@;VTtGi_##J|#sh0e1SC`p>j^|bUrbc!) z?3ka9Lu>6C{s(K%JWdR1nDT0w_@b{)xn6`8M6+)LCT(DLkW~~rR`mnws{n*RRoJ$b z^hdsNka(flFN9bIt|YD4HFAxv?FKAp47=xcQh;|5$~ZYW!-o_V~xd;<;_mW%Wa z=o@=$N%3R~4~>nadt1{=mj#$?*gqi?!K>NyNp9$#p_LI1CG;{j`KZ~igqjGW0(0lS z6t5PO>KbRp@6v%H_IZ<%M-=BQbl5>iZ{kD1&Y2?!LH@d{+sg0oQ;2|P*;`m)<7;Q{ z*VQy6@{rSC6X2ER&ubSeJ2j-h++y*v_t(u~r&YM$A%c2%hDg{&pUBd1;seK_*4&I$ zk6{^^;JPYH|4{Cp2&^-Z1VeFs-v2*h;K~$65xLIHsnxs~je3U{bz8}nQ0{*L!S5S# literal 0 HcmV?d00001 diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3775920b702906b199ec243cfbcf09c5606f2fea GIT binary patch literal 22406 zcmeI42{_c-`@p}YC`#QnRBDKlj9D|2Xeq@qYD zZPt($3Q^hGaHFVf|L<7xt@N9FyZ8Tp{{QDc^E}O*&UxSWobx&F`=0kZo@WkiHP)Li zxLgnbfcXac+GYSSYdP3{Ifoy7e{Ob41^k%H(6?a$fczTHzZqU>>K*_fXhPG{+Pc+= z&Ze`R=nR;FmKKb`q*G`vWB~ALNHV8dn7>}8HqiV*bIU>hqg&`^OXtAMG(-HCM68vS zn7eTEL5br}mzv)EO-EfWx}qJ01f5NuT2O%m8eUN-Uj`8Uer-lMiYGP8)&Dnr(-5 z0Ba<$gtFxh7I*>&kOo#1ec)mqP+YxGC>xkF4?vn8Jg^>^wFhu0TeHRs*dGTh(e1TT zeZL`VVW%ueDlS_!Uka-eU^@rCTfoXnew9qMfyjm>7{W|K{3iKZ-f?2+0L2B*`|bfi zYQ$1-w|&E2)xufT)tInc;hpd|H~2>-9UWUo+G{cxn*iVi+pl&+4w19me&OY| z?paRuLaFWpA(ZR|o2~$ zK9ZTk=kFBwqQ-NyM}1f?RT}W87)0&{0DEmId5el1_0l;2pq&~Zdr@P>hnu2u#r!L8 z&ThIXG~|HUuPJrsmgYiDL6ZMUro;NoeVQ^sRTsr&9T1N;i7OVHIt4{BgynBpUKLhj zEcim0lYCRAFktR1jj}n52@(wlXE+|VUK2J)B<{c`iJSVf7KKQ`$`39vmE01cq>nN? zYyq>>7w=VL&cp`q(7hJ1u?#@(8wx7aLmdssHdT8x?}}Fb8Rg~sbx#Q0C$UlS;mcAJ z?lUhhR|~})@4TPkw4fmzuT_dHekCfPaK{BHUvgXXl8W5iC}QO$$;^2fCCe{v%j7FK z^pRL|$#d4C0G;Bwm|32hFv2PgeQQH&<0txOU@N5*e`}blJeP03>8*8=QD?SXUVH7g z&v!%}(Wqc+eYrJti^3Np7VbHybw^oh(IGALy8I(E4KAIsc(CY!?gKZoHLvB)CMfDJ zUlUc{KyuC&z#f%@Z74g?meh8;O`&Z?n?$dzV3Ome-KRd8zmzen*tJ=#ePO#|J3l!V ztzmgG-t5_#;}*Xug>Tn9e>~Uhf@$!X#ft9n*s8!~23yk3pE&k#xs!;~0PVsn_O;)h z9b07_bKmMgzK~zALD&{GAA=dD;*uxO9QVXOq>TPUi z+=4i|rL}CX?B1mj6@te$A6t8Dg)GA2?77qDn$HPY_E}b1grBuH_s!C^R4{KnJNHp^ zhUK}Wt#8d&m{ZSgJQIA5dWLSHe#*~g_z=I%ZNu9pTBl4?FYRnCEP)9T#d5slB%J4G z1i1$&-C297>giq&*@D<%@q!Swb7zlZwG=ihSml`Y9i^xXw8rlKl*l%o+bNSC)8}`% zc}dUum+M!YRy52=&Cq*WgvshkPdZ(sQ(!X~AgockdEJh6derdh z*-4$|PtBjD3#KnKQp0`Bl0WC1w&Hk!w&xAE^zPW?>-PT1hV=Ai@1o8xD}52e7Q?Pz z(m(3Wv*yp4C&k}5uUb^~uF`J0syL#w@x7^*-R(_UX@p~hm>2sa@@rL3KGyw1cR?tv zWJjx1t80mC$;q|+YbDlhF?wUv9dBloe|r7tjfNWyORMfxov5mdQ%X=n)uTHTIuq&> zTJjvWdu^A?J(GKtY>?fy{j^PYZlT+O?O2;MYs>9+IlAYQ&P&%7oG(cKEj`~j$~Ysr zj(Ypz``q%}vw30{+n?|^X63r(`Vy#)BGkOQS+~2RilTh4`TjAiCNMwvsc?q)c5y$} zW#$sxHe7Rjbz--=@7)j4uMt%1nuRq_6k2l^SFXQ9OEOP*s7Do{=CcC(4u%}svaeD; z1}~qmqU2dwQQKzr$K7@>d>(vEO2|pL)pe%vLN}(H)*alGa!)a3eX@-L>;COBt>>og zwdz7C$B@n~nSLf(CIQqdoof(8M1RzIjBd8sc~7}G zuPm?9 z*I23%zVH0L_M7J=oXXxEIWIBL8CxAuO%pz_)$di^eE~uTA>_8-ymbeH4_F1MhcOOX zFRw+#D0$X4X|Ydq1HVjv4}D|hWGL6TOSUjFFPy0NDddh$?%}D%F#bH7RsJk z7AoDl*i$-8(EFD7Evh7<7E^ohiPjF;RmQ#gvPM3U?;;A7yru3cq{+4C?_YQJNTK0; z!)FP&MXL0hcg z;?^BSnY*yrs=K`#1zVTS-Vn5nKU4MU;apkQ$0iwFRxw$AMQeSGoCEA{R_wcZWrp)x zAxpvb1HNyY>bvYrtPwUXR|sE%l2+iC9y*-0q){Yh>F-Zun!MUq1k)>S#5Engd^Y1w zKBRE@*z5WzE=xTS~*mZYTDc=LWVSzQmx%K&v9*aLvvoH&<+wfLTxODaPk)$3^_5jeZzjEIuiBJq_iNhAU-R9hjV_nPtlb< zl!4bPl9j8UeJJvNzihPbaWYozSy7)4ecS%&cY^!ROkb!}|z@tEG2s2i?((}v#^zZJXCSaPdm)%9{O z1(f}VZG&AmJ)1nmdrr12FlpNh`(0+#>GP$J=J(SFqr{@3MrZNG_6-pg;Ee#Fae`)H z&9*iZMP@&ppyku2}!$^Z*d08mx;Vi1VVWH!u^Or^Q0N%j=nkc81lYLZq;Mo1%u z7TJlW@53aU`xsjgeVmC{lB7CbP}K_u8gM1E2{12L7dIBpOHFdjE)HySx)GAFF%h=2 znxqD2LYTGDR+tu@NroxOW8g%Tf(lF-E00pbs-P9+U}z)?gFs>tC`C9Dg+pR-NEB@1 zC5aaVTdGVF1!tzMJ24&jKQ&1wHk*M%AUr)izP={*<;wUvksE7*9Y_)3MPMLM z@<_yVN+jY}9fmv8Wo&6AB7*Efb|t&9S)d+jT0Ib{kgN!gEv*_+jB3Z`+T*;d07SCdvk*DDP1yi8-w1yayk22G*>+A4OF|uitpDctk z@>4ak7wso%oRM+0F`pVgYE_UrPK!w$hLBobm|T=F{`Mqn6`2yDWn z6;Mq9j>1}?Q8*?IG4aDR`ZN~kb>0wf1buQW)tQrbf7?4b;6fWqSquV`Mdn1bn&f0i zf6Z}UQy52QEHmH;L{7596FF{9CaEI6>782ESIr4E+K)%cef#6KA*w&O@99K#`%eKf zZfZ>G=SEm`3fq&wBx_JX&-gKV%@tu^19x)c->Q6XS{1>$6kKTk4F|v?c>FW`7z!4x zLQo{Y$sFHSBoQ%i0+FZ!Cs8npXcaOROTmJP3gN%d=v!fDZ6=u9IziHrv;w&}VdHm8QcKW1zl|62y0 zWu~VIGtkk(ps*MW94(K6nt{koYsZ4@#Wo~(b294GIOm$+IDsaC`fcyzz~8Nzrq(?+ zmob>c@g#Rg2F;7?0$uIY=r@ZQuc9E##^g9l|GAa1(eJJNyM@UA?p=-V_1hzavYz(j zRXGoWIIz+NE5EU86%TsT4}DWu$K|a#6|;-`SVfEmzcIjKkq8tLd`;*=$G_LL;i3y2 z|6X@W)zXc|#-k^u`>q?J#d%&G4>)u1I~p=)bKiG;FTIuHqt@Cq@F|JKsrXSyC2(6~ zTHg;%t7#9edE30S2f_bM2N3n6a5gF<3aK-zfW!HUp5Ri z$D0I7gKL|Iiz_0i01p?G2G=$Z7gt130Uje`xaB)Qh72x55(%{@lBB%fl z7nBCqHV+q9L{I@9E+`GIZ5}SJh@b*ITu>TZ+y4=l;M5NAOL(G1wUT{fIAWZ-Z%gNE*1bp=#e|`>H>fepMkc9g;&G7#v2(s zsp0~E4xEf>*jKl3&QaY{C$_$Rv`;_R<-y(6PX+B7uBr5^&oK@YDF`X=5G{*7&SqQ` z&JEl@FDS?`ZU2d_8{Yh>qGH?A<=ZkijPD%u=_((<)_AAXU^}bSh}B}?viyTCJedi8 zrs~v!@4zD&&d-|pFW2D%KenE9;`HrWG9P^3^v8)A;KvzLMNXg6Va^YqrRx6wQVR1Z z@<#>bY(;k#9&LLtbIUL(^nJcU3D#c7MB3XgAk8nj?a=4B0_r)*MojMmaY`j#FGHnS z#x*ydi_y!)_SSuNH`9B0Z9RQmett2IE|uTP-W_JYx%cMGw}nY<^V5Zdn{5rks^t8u zR9nS|=Jmgx1v37%Ltv4FFzrP;b)SpRzD)E@Y>N@f?9)mY)bABg5OOfD@e)uEEKOwP z35nirpSki>PW8^d#l=JXSIfW^;*&TB{5KDsb@>WkJPV)DmTg{8j~65E^{eRnViDOX zqLN!vB5JbisasbMDV*Rsl0v?yjK#j zvfI7=deQ1B6VmU;>7Du&7iL|)NxYWO76I<1d34ce$4M#WWh%L)A&G%4(w`XF;=zR$cTc0{SJo|yf{&{c|fNco3f?1Y3AVPTG3W|x+=yd;uySxd}v-p$Y)7J zMjFw+!!53NIB+=`L?V23NhX>#mp0NsGJ@;xnq=@Sai>+ZH(6_)V7-UG8G_ zPN@lpT(cpYY0N>JLE376PsAIwvtJ_c!a8i-f=7jMZFR|+cUNM9J!!|DW^W#e{KV!Y z4jHpwNeJV+s*f6S2=M*l75d(xMFiWqSE5`<=v`+@si=vuw@bF<2HSg;i^PtK^y%2& zi}5Xcp4ew=aJ}<=QO8Zu)>gH+6&)9`g_XnG$+;H2o~Avc1@g<$CCH9|Kz7|{XTO=T zEr1C2hH*vuVsMpzH+zM73=PI~CaT*wq>P|TJ`G<-FsnZ^BV$CK)OePPhMRc1#6*=H z&UBGS7_@O#cc7PPyr`!0{Rjfl2}+xkkNf~yD$UV9Y0>UD1CMGbib z_+BfzRk2ocbiys^{ z5_m}>E9S=NW2qKva63vRpZ1Q?#+5$=X}6S$j^f)dm4ll>BMh#y?Mp;^nGWE|d!)p$ z8ged3d+YLd4U2s06m4BSu^ra)my^Kd-)V?BELc73o(a&m!XfV0(?@H|4Rq&TUyzP^ z$<@4`kVKaK7N%>!aN))hFRuz>L8SIJ5}D;~Ac^R`HR?$Z-TixpfO6+v>2mjht5xqF z8id_-CkrRsru@0KMWH{<>1uqN*Cc7HsHPnbN#T*IN0-`Q(=*FL3SE>qxnn3Vw(;Cs zO5N%Ha!|K2L~L(a%^wDPahz*z$@*Wp2Sc%)ZX(E_9N@c@I`R*$PHe;bo}F>5>(`6% z&sGzg8ad&AK{`LT*smGP2CD6s>?D)d3 z@ah^G^xS*T`KnV))`3KRttN;^bvAX)EMYA3|1K(b{z}%Es6F&-H>P4c!=r|p&Yt(C zhQ9A!w!m;(^q(21lEL0y^?Fh+yZ`-0gD{aNIbf{zhzfP`L$Xp6q{}b;sj)ecs15^#pVcDd5(_q0TwC!S+CHuVH{Ql MI>y>rnhyK^3nnOSR{#J2 literal 0 HcmV?d00001 diff --git a/images/logo_HF.png b/images/logo_HF.png new file mode 100644 index 0000000000000000000000000000000000000000..3cfe116b1dc21a4ef00f55030ecd71bba958b9f4 GIT binary patch literal 5057 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 X^>2QqQ(MNt00000NkvXXu0mjfy5plv literal 0 HcmV?d00001 diff --git a/images/pcb_front.png b/images/pcb_front.png new file mode 100644 index 0000000000000000000000000000000000000000..d62c49a33f88c20048037e124462de600c22e48e GIT binary patch literal 5196 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 T$qAEyM7?jXH@$3kXu|&if^9mE literal 0 HcmV?d00001 diff --git a/images/pcb_rear.png b/images/pcb_rear.png new file mode 100644 index 0000000000000000000000000000000000000000..4c97f3dbfcc547ec418c52de98df606703135f63 GIT binary patch literal 5099 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 literal 0 HcmV?d00001 diff --git a/images/rear.png b/images/rear.png new file mode 100644 index 0000000000000000000000000000000000000000..077b3118b26e50e348526f2bc30230ae51f5134f GIT binary patch literal 5090 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 K*TO%OS^oxuqwvrG literal 0 HcmV?d00001 diff --git a/images/rear_render.png b/images/rear_render.png new file mode 100644 index 0000000000000000000000000000000000000000..2b7e4595afec3b1806e429b6142d041e33aa4081 GIT binary patch literal 5024 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 bfbq&an>gCUY5J`Lx#hUWWp~j|a{PY*!XnG9 literal 0 HcmV?d00001 diff --git a/readme.md b/readme.md index 762be9bd43..84c7605004 100644 --- a/readme.md +++ b/readme.md @@ -1,103 +1,246 @@ -

- - - - - - - - -

- -# Welcome to WLED! ✨ - -A fast and feature-rich firmware for ESP32 microcontrollers to control addressable LEDs — from simple strips to large 2D matrices and HUB75 panels. - -Originally created by [Aircoookie](https://github.com/Aircoookie), now maintained by a community of contributors. - -## ⚙️ Features - -### Effects & Visuals -- [**200+ built-in effects**](https://kno.wled.ge/features/effects/) including classic animations, audio-reactive, and 2D/matrix effects -- [50+ color palettes](https://kno.wled.ge/features/palettes/) plus a built-in **custom palette editor** (PixelForge) -- [**2D LED matrix support**](https://kno.wled.ge/advanced/mapping/) with dedicated 2D effects and flexible panel mapping -- [**HUB75 RGB matrix panel support**](https://kno.wled.ge/advanced/HUB75/) (ESP32) -- [**AudioReactive**](https://kno.wled.ge/advanced/audio-reactive/) effects — included by default, responding to sound via microphone, line-in, or network audio source -- Effect blending for smooth transitions between animations -- Antialiased drawing functions for smooth graphics - -### Segments & Control -- [**Segments**](https://kno.wled.ge/features/segments/) — apply different effects, colors and palettes to independent parts of your LED setup simultaneously -- Up to **250 presets** to save and recall colors, effects and segment configurations — supports [playlists](https://kno.wled.ge/features/presets/) for automated cycling -- Nightlight function with configurable dimming curve -- Configurable **Auto Brightness Limiter** (per output) for safe operation - -### Hardware Support -- **ESP32** (all variants: original, S2, S3, C3) -- [**Up to 17 LED outputs**](https://kno.wled.ge/features/multi-strip/) on ESP32 using parallel I2S + RMT -- [Addressable LED support](https://kno.wled.ge/basics/compatible-led-strips/): WS2812B, WS2811, WS2815, SK6812, WS2805, TM1914, APA102, WS2801, LPD8806, and many more -- RGBW, [RGB+CCT](https://kno.wled.ge/features/cct/) and white-only strips -- PWM outputs for analog LEDs and dimmers -- [**Ethernet** support](https://kno.wled.ge/features/ethernet-lan/) for a wide range of boards (QuinLED, LILYGO, Olimex, and more) -- Filesystem-based config for easy backup and restore of presets and settings -- Full OTA firmware updates (HTTP + ArduinoOTA), password-protectable - -### Connectivity & Integrations -- **WLED app** for [Android](https://play.google.com/store/apps/details?id=ca.cgagnier.wlednativeandroid) and [iOS](https://apps.apple.com/gb/app/wled-native/id6446207239) -- [JSON](https://kno.wled.ge/interfaces/json-api/) and [HTTP request](https://kno.wled.ge/interfaces/http-api/) APIs -- **Multi-WiFi** — connect to up to 3 networks with automatic AP fallback -- **ESP-NOW** wireless sync between devices (no WiFi router required) -- [**MQTT**](https://kno.wled.ge/interfaces/mqtt/) with Home Assistant discovery -- [**E1.31, Art-Net**](https://kno.wled.ge/interfaces/e1.31-dmx/), [DDP](https://kno.wled.ge/interfaces/ddp/) and [TPM2.net](https://kno.wled.ge/interfaces/udp-realtime/) for DMX/professional lighting control -- [UDP realtime sync](https://kno.wled.ge/interfaces/udp-notifier/) across multiple WLED devices -- Alexa voice control (on/off, brightness, color) -- [Philips Hue sync](https://kno.wled.ge/interfaces/philips-hue/) -- [diyHue](https://github.com/diyhue/diyHue) and [Hyperion](https://github.com/hyperion-project/hyperion.ng) integration -- [Adalight / TPM2](https://kno.wled.ge/interfaces/serial/) (PC ambilight via serial) -- [Infrared remote control](https://kno.wled.ge/interfaces/infrared/) (24-key RGB, receiver required) -- Timers and schedules (NTP time sync, full timezone and DST support) - -### Developer-Friendly -- **Usermod system** — extend WLED with community or custom modules without modifying core code -- Large and active [usermod library](https://kno.wled.ge/advanced/community-usermods/) including AudioReactive, temperature sensors, rotary encoders, displays, and much more -- Well-documented [JSON API](https://kno.wled.ge/interfaces/json-api/) -- Licensed under the **EUPL v1.2** - -## 📲 Quick start guide and documentation - -See the [documentation at kno.wled.ge](https://kno.wled.ge)! - -[Tutorials and getting-started guides](https://kno.wled.ge/basics/tutorials/) to help you get your project running quickly. - -## 🖼️ User interface - - - -## 💾 Compatible hardware - -See the [compatible hardware list](https://kno.wled.ge/basics/compatible-hardware) on the wiki. - -## ✌️ Other - -Licensed under the [EUPL v1.2](https://raw.githubusercontent.com/wled-dev/WLED/main/LICENSE). -Credits to all [contributors](https://kno.wled.ge/about/contributors/)! -CORS proxy by [Corsfix](https://corsfix.com/). - -Join the Discord server to discuss everything about WLED! - - - -Check out the WLED [Discourse forum](https://wled.discourse.group)! - -If you'd like to reach the original creator privately: [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com). - -If WLED brightens up your day, you can [send a gift to Aircoookie via PayPal](https://paypal.me/aircoookie). - ---- - -*Disclaimer:* - -If you are prone to photosensitive epilepsy, we recommend you do **not** use this software. -If you still want to try, avoid strobe, lightning or noise modes and high effect speed settings. - -As per the EUPL license, no liability is assumed for any damage to you or any other person or equipment. + + + + + + + + + + + + + + + + + + + +
+ +[![Contributors][contributors-shield]][contributors-url] +[![Forks][forks-shield]][forks-url] +[![Stargazers][stars-shield]][stars-url] +[![Issues][issues-shield]][issues-url] +[![License][license-shield]][license-url] +[![LinkedIn][linkedin-shield]][linkedin-url] +
+ +
+ + Logo + +

dpx_tc002_frm

+

a sassy project tag line here

+

+ ...a short description to tease interest +
+ » + Project Here! + » + BOM Here! + » + Interactive BOM Here! +
+ Report Bug + · + Request Feature +

+
+
+ +
+

Table of Contents

+
    +
  1. + About The Project + +
  2. +
  3. + Getting Started + +
  4. +
  5. Usage
  6. +
  7. Reflection
  8. +
  9. Roadmap
  10. +
  11. Contributing
  12. +
  13. License
  14. +
  15. Contact
  16. +
  17. Acknowledgments
  18. +
+
+ +
+

About The Project

+a lengthy description about the project that should probably be many lines. this is where you can get deep about shit and be like oh man its the best hot dog in the univberse because i use the koskusko mustart! +
+ +*author(s): // www.dubpixel.tv - i@dubpixel.tv | other authors* +
+

Images

+ +### FRONT +![FRONT][product-front] +### REAR +![REAR][product-rear] +### FRONT Rendering +![FRONT][product-front-rendering] +### REAR Rendering +![REAR][product-rear-rendering] +### iBOM PCB Front +![iBOM Front][product-pcbFront] +### iBOM PCB Rear +![iBOM Front][product-pcbRear] +
+

(back to top)

+ +### Built With + + * [![KiCad][KiCad.org]][KiCad-url] + * [![Fusion360][Fusion-360]][Autodesk-url] + * [![FastLed][FastLed.io]][FastLed-url] + + +

(back to top)

+ + +## Getting Started + + ### Prerequisites + * + ### Installation + + 1. + +

(back to top)

+ + +## Usage + +1. + +## Reflection + +* what did we learn? + - _x_ +* what do we like/hate? + - _y_ +* what would/could we do differently? + - _z_ + +## Roadmap + +- [ ] Feature 1 + - [ ] Nested Feature + +See the [open issues](https://github.com/dubpixel/dpx_tc002_frm/issues) for a full list of proposed features (and known issues). + + +## Contributing + +_Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**._ + +If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". +Don't forget to give the project a star! Thanks again! + +1. Fork the Project +2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) +3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) +4. Push to the Branch (`git push origin feature/AmazingFeature`) +5. Open a Pull Request + +### Top contributors: + + contrib.rocks image + + + +## License +Distributed under the [LICENSE_TYPE] License. See `LICENSE.txt` for more information. + +## Contact + + ### Joshua Fleitell - i@dubpixel.tv + + Project Link: [https://github.com/dubpixel/dpx_tc002_frm](https://github.com/dubpixel/dpx_tc002_frm) + + +## Acknowledgments + + + +

(back to top)

+ + + +[contributors-shield]: https://img.shields.io/github/contributors/dubpixel/dpx_tc002_frm.svg?style=flat-square +[contributors-url]: https://github.com/dubpixel/dpx_tc002_frm/graphs/contributors +[forks-shield]: https://img.shields.io/github/forks/gdubpixel/dpx_tc002_frm.svg?style=flat-square +[forks-url]: https://github.com/dubpixel/dpx_tc002_frm/network/members +[stars-shield]: https://img.shields.io/github/stars/dubpixel/dpx_tc002_frm.svg?style=flat-square +[stars-url]: https://github.com/dubpixel/dpx_tc002_frm/stargazers +[issues-shield]: https://img.shields.io/github/issues/dubpixel/dpx_tc002_frm.svg?style=flat-square +[issues-url]: https://github.com/dubpixel/dpx_tc002_frm/issues +[license-shield]: https://img.shields.io/github/license/dubpixel/dpx_tc002_frm.svg?style=flat-square +[license-url]: https://github.com/dubpixel/dpx_tc002_frm/blob/main/LICENSE.txt +[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555 +[linkedin-url]: https://linkedin.com/in/jfleitell +[product-front]: images/front.png +[product-rear]: images/rear.png +[product-front-rendering]: images/front_render.png +[product-rear-rendering]: images/rear_render.png +[product-pcbFront]: images/pcb_front.png +[product-pcbRear]: images/pcb_rear.png +[Next.js]: https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white +[Next-url]: https://nextjs.org/ +[React.js]: https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB +[React-url]: https://reactjs.org/ +[Vue.js]: https://img.shields.io/badge/Vue.js-35495E?style=for-the-badge&logo=vuedotjs&logoColor=4FC08D +[Vue-url]: https://vuejs.org/ +[Angular.io]: https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular&logoColor=white +[Angular-url]: https://angular.io/ +[Svelte.dev]: https://img.shields.io/badge/Svelte-4A4A55?style=for-the-badge&logo=svelte&logoColor=FF3E00 +[Svelte-url]: https://svelte.dev/ +[Laravel.com]: https://img.shields.io/badge/Laravel-FF2D20?style=for-the-badge&logo=laravel&logoColor=white +[Laravel-url]: https://laravel.com +[Bootstrap.com]: https://img.shields.io/badge/Bootstrap-563D7C?style=for-the-badge&logo=bootstrap&logoColor=white +[Bootstrap-url]: https://getbootstrap.com +[JQuery.com]: https://img.shields.io/badge/jQuery-0769AD?style=for-the-badge&logo=jquery&logoColor=white +[JQuery-url]: https://jquery.com +[KiCad.org]: https://img.shields.io/badge/KiCad-v8.0.6-blue +[KiCad-url]: https://kicad.org +[Fusion-360]: https://img.shields.io/badge/Fusion360-v4.2.0-green +[Autodesk-url]: https://autodesk.com +[FastLed.io]: https://img.shields.io/badge/FastLED-v3.9.9-red +[FastLed-url]: https://fastled.io From ddeecc476e5f0132fa668df97ad2dcfe3079a629 Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Fri, 17 Jul 2026 22:46:42 -0400 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20dpx=5Fmatrix=20usermod=20=E2=80=94?= =?UTF-8?q?=20TC001=20LED=20matrix=20display?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AwtrixFont (BSD-3-Clause TomThumb), MQTT, OSC, text overlay - Pixel effects: sparkle, twinkle, strobe, blink, rain - First-boot cfg.json template (behav:1, dpx-tc002 AP, GPIO32 256 LEDs) - Buzzer RTTTL support - Loop rate-limited to 50Hz; UDP open deferred to connected() - platformio_override.ini: ulanzi_tc001 USB env, shared build flags - tools/ltc_osc_bridge: LTC→OSC bridge utility --- ARCHITECTURE.md | 111 ++ dpx_tc002_frm.code-workspace | 23 + platformio_override.ini | 65 + ...LTC_01000000_5mins_30_NDF_FPS_48000x16.wav | Bin 0 -> 28800134 bytes tools/ltc_osc_bridge/Launch LTC Bridge.bat | 5 + .../ltc_osc_bridge/Launch LTC Bridge.command | 6 + tools/ltc_osc_bridge/OSC_BRIDGE_HANDOFF.md | 233 +++ tools/ltc_osc_bridge/ltc_osc_bridge.py | 896 +++++++++++ tools/ltc_osc_bridge/ltc_osc_bridge_gui.py | 1155 ++++++++++++++ tools/ltc_osc_bridge/pyproject.toml | 24 + tools/ltc_osc_bridge/requirements.txt | 4 + usermods/dpx_matrix/dpx_api.h | 386 +++++ usermods/dpx_matrix/dpx_apps.h | 372 +++++ usermods/dpx_matrix/dpx_buzzer.h | 201 +++ usermods/dpx_matrix/dpx_firstboot.h | 104 ++ usermods/dpx_matrix/dpx_font.h | 146 ++ usermods/dpx_matrix/dpx_html.h | 1366 +++++++++++++++++ usermods/dpx_matrix/dpx_matrix.cpp | 17 + usermods/dpx_matrix/dpx_matrix.h | 126 ++ usermods/dpx_matrix/dpx_mqtt.h | 208 +++ usermods/dpx_matrix/dpx_notifications.h | 86 ++ usermods/dpx_matrix/dpx_osc.h | 237 +++ usermods/dpx_matrix/dpx_overlay.h | 242 +++ usermods/dpx_matrix/dpx_persist.h | 107 ++ usermods/dpx_matrix/dpx_tc.h | 111 ++ usermods/dpx_matrix/dpx_text.h | 174 +++ usermods/dpx_matrix/library.json | 5 + wled00/const.h | 1 + 28 files changed, 6411 insertions(+) create mode 100644 ARCHITECTURE.md create mode 100644 dpx_tc002_frm.code-workspace create mode 100644 platformio_override.ini create mode 100644 tools/ltc_osc_bridge/LTC_01000000_5mins_30_NDF_FPS_48000x16.wav create mode 100644 tools/ltc_osc_bridge/Launch LTC Bridge.bat create mode 100755 tools/ltc_osc_bridge/Launch LTC Bridge.command create mode 100644 tools/ltc_osc_bridge/OSC_BRIDGE_HANDOFF.md create mode 100644 tools/ltc_osc_bridge/ltc_osc_bridge.py create mode 100644 tools/ltc_osc_bridge/ltc_osc_bridge_gui.py create mode 100644 tools/ltc_osc_bridge/pyproject.toml create mode 100644 tools/ltc_osc_bridge/requirements.txt create mode 100644 usermods/dpx_matrix/dpx_api.h create mode 100644 usermods/dpx_matrix/dpx_apps.h create mode 100644 usermods/dpx_matrix/dpx_buzzer.h create mode 100644 usermods/dpx_matrix/dpx_firstboot.h create mode 100644 usermods/dpx_matrix/dpx_font.h create mode 100644 usermods/dpx_matrix/dpx_html.h create mode 100644 usermods/dpx_matrix/dpx_matrix.cpp create mode 100644 usermods/dpx_matrix/dpx_matrix.h create mode 100644 usermods/dpx_matrix/dpx_mqtt.h create mode 100644 usermods/dpx_matrix/dpx_notifications.h create mode 100644 usermods/dpx_matrix/dpx_osc.h create mode 100644 usermods/dpx_matrix/dpx_overlay.h create mode 100644 usermods/dpx_matrix/dpx_persist.h create mode 100644 usermods/dpx_matrix/dpx_tc.h create mode 100644 usermods/dpx_matrix/dpx_text.h create mode 100644 usermods/dpx_matrix/library.json diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000000..296db05ff4 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,111 @@ +# dpx_tc002 — Architecture & Decisions + +**Date:** 2026-07-17 +**Status:** Firmware repo pending setup + +--- + +## Repo Structure + +| Repo | What it is | +|------|------------| +| `dpx_tc002` | Product repo — hardware, docs, tools, this file | +| `dpx_tc002_frm` | Firmware — fork of `wled/WLED` (MIT), separate GitHub repo | +| `dpx_tc001/dpx_reference` | Reference only — AWTRIX-derived, do not copy license-unsafe files | + +`dpx_tc002_frm` is a clean fork of WLED mainline (`wled/WLED`, `main` branch). No nested git repos, no submodules. + +--- + +## Why WLED Fork (not AWTRIX) + +dpx_tc001 was a fork of AWTRIX 3 (CC BY-NC-SA 4.0) — that license blocks commercial use. +dpx_tc002_frm is a WLED fork (MIT) — commercially clean, no share-alike requirement. + +### Why mainline WLED and not MoonModules/WLED-MM + +MoonModules adds 2D effects and experimental features, but dpx_tc002 writes its own display layer on top. The extra effect catalog adds maintenance burden with no benefit. Mainline 2D matrix support is sufficient for a 32×8 pixel array. + +--- + +## What dpx_tc002_frm Will Contain + +Full WLED source with one custom usermod added: + +**`usermods/dpx_matrix/`** — original work, MIT: +- 5×7 pixel bitmap font (new — NOT the AWTRIX font) +- Text rendering + scrolling (`renderText`, `renderScroll`) +- App loop system (named display slots, auto-rotation timer) +- Notification queue (interrupts loop, auto-dismisses) +- OSC receiver on UDP port 4210 — d3 disguise integration, `/tc` timecode +- HTTP API matching dpx_tc001 contract (`/api/custom`, `/api/notify`, `/api/tc`, etc.) +- Web UI pages served from PROGMEM: `/ctrl`, `/browse`, `/api-ref` +- TC display with frame-accurate progress bar (two render modes) +- 3 indicator pixels (corner dots, addressable via `/api/indicator1/2/3`) +- dev.json persistence (temp offsets, LDR config, TC dwell settings) +- OSC Listener Registry (d3 monitoring path → display channel mappings) + +--- + +## What Gets Stripped / Disabled + +Handled via compile-time flags in `platformio.ini` — no source deletion needed: + +```ini +-D WLED_DISABLE_ALEXA +-D WLED_DISABLE_LOXONE +-D WLED_DISABLE_INFRARED +-D WLED_DISABLE_HUESYNC +-D WLED_DISABLE_ADALIGHT +-D WLED_DISABLE_ESPNOW +``` + +Most of the 100+ WLED effects can be pruned later if flash is tight. The WLED stock web UI (`wled00/data/`) is superseded by the custom pages served from the usermod — keep it in but redirect `/` to `/ctrl`. + +--- + +## Hardware Target — Ulanzi TC001 + +ESP32-WROOM-32D · 240MHz · 4MB flash (1.75MB app + 256KB LittleFS) · CH340 USB-serial + +| GPIO | Function | +|------|----------| +| 32 | LED matrix data (256× WS2812B, 32 cols × 8 rows) | +| 26 | Left button (active low) | +| 27 | Middle button (active low, inverted) | +| 14 | Right button (active low) | +| 15 | Passive buzzer — RTTTL via PWM | +| 34 | Battery ADC (read-only voltage divider) | +| 35 | LDR — auto-brightness (GL5516) | +| 21 / 22 | I²C SDA / SCL — SHT3x temp + humidity (addr 0x44) | +| 23 / 18 | DFPlayer Mini RX / TX (optional) | + +**Matrix layout:** row-major, left-to-right, top-to-bottom. Pixel index = `row * 32 + col`. + +--- + +## License Boundaries + +**Do NOT copy (AWTRIX-derived, CC BY-NC-SA 4.0):** +- `AwtrixFont.h` +- `MatrixDisplayUi.cpp` +- `MQTTManager.cpp` +- The `/setup` page from `htmls.h` + +**Safe to port (original work from dpx_tc001 session):** +- `tools/ltc_osc_bridge/` — copy verbatim, 100% original Python, MIT-clean +- `/ctrl`, `/browse`, `/api-ref` HTML pages from `htmls.h` +- OSC `handleOSC()` logic from `ServerManager.cpp` + +--- + +## Next Steps + +1. Fork `wled/WLED` → `dubpixel/dpx_tc002_frm` on GitHub, clone locally +2. Update `dpx_tc002.code-workspace` to include `dpx_tc002_frm` as the firmware folder +3. Verify WLED builds clean: `npm ci && npm run build && pio run -e esp32dev` +4. Create `usermods/dpx_matrix/` skeleton (header files only, empty stubs) +5. Configure `platformio.ini` env for Ulanzi TC001 with `custom_usermods = dpx_matrix` +6. Build Phase 1 — font + text rendering + +See `⊘ dpx_reference/dpx_tc002.md` for the full phased build plan (Phases 1–8). diff --git a/dpx_tc002_frm.code-workspace b/dpx_tc002_frm.code-workspace new file mode 100644 index 0000000000..f23805033f --- /dev/null +++ b/dpx_tc002_frm.code-workspace @@ -0,0 +1,23 @@ +{ + "folders": [ + { + "name": "dpx_tc002_frm", + "path": "." + }, + { + "name": "⊘ dpx_reference", + "path": "../dpx_tc001/dpx_reference" + }, + { + "name": "⊘ dpx_showsite_ops", + "path": "/Users/yourmom/Code/DPX_SHOWSITE_OPS" + } + ], + "settings": { + "files.readonlyInclude": { + "**/dpx_reference/**": true, + "**/WLED/**": true, + "**/dpx_showsite_ops/**": true + } + } +} \ No newline at end of file diff --git a/platformio_override.ini b/platformio_override.ini new file mode 100644 index 0000000000..7f2c899650 --- /dev/null +++ b/platformio_override.ini @@ -0,0 +1,65 @@ +; ================================================================================ +; platformio_override.ini — dpx_tc002 / Ulanzi TC001 Build Config +; ================================================================================ +; Ulanzi TC001 hardware: +; ESP32-WROOM-32D · 240MHz · 4MB flash · CH340 USB-serial +; LED matrix: GPIO32, 256× WS2812B, 32×8 rows, row-major +; LDR: GPIO35 I²C: GPIO21/22 Buttons: GPIO26/27/14 +; +; Usage: +; pio run -e ulanzi_tc001 # build only +; pio run -e ulanzi_tc001 -t upload # build + flash +; +; First time: +; npm ci && npm run build # generate html_*.h headers +; pio run -e ulanzi_tc001 +; ================================================================================ + +[env:ulanzi_tc001] +extends = env:esp32dev + +; ── Hardware ────────────────────────────────────────────────────────────────── +board = esp32dev +board_build.mcu = esp32 +board_build.f_cpu = 240000000L +upload_speed = 460800 + +; ── Custom usermod ──────────────────────────────────────────────────────────── +custom_usermods = dpx_matrix + +; ── Compile-time flags ──────────────────────────────────────────────────────── +build_flags = + ${env:esp32dev.build_flags} + + ; ── Disable unused WLED features to save flash ────────────────────────── + -D WLED_DISABLE_ALEXA + -D WLED_DISABLE_LOXONE + -D WLED_DISABLE_INFRARED + -D WLED_DISABLE_HUESYNC + -D WLED_DISABLE_ADALIGHT + -D WLED_DISABLE_ESPNOW + + ; ── Ulanzi TC001 hardware pin defaults ───────────────────────────────── + ; These are compile-time defaults. The user can override via WLED web UI. + -D LEDPIN=32 + -D BTNPIN=26 + -D RLYPIN=-1 + -D IRPIN=-1 + -D STATUSPIN=-1 + + ; ── LittleFS instead of SPIFFS ───────────────────────────────────────── + -D WLED_USE_LITTLEFS + + ; ── Product identification ───────────────────────────────────────────── + -D WLED_VERSION='"dpx_tc002-dev"' + -D WLED_PRODUCT_NAME='"dpx_tc002"' + -D WLED_INSTANCE_NAME='"dpx_tc002"' + +; ── Custom partition table (1.75MB app + 256KB LittleFS) ───────────────────── +; board_build.partitions = tools/TC001_partitions.csv +; Uncomment the line above once the custom partition table is added. +; For now, uses esp32dev default (1.25MB app). + +; ── Monitor ─────────────────────────────────────────────────────────────────── +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder diff --git a/tools/ltc_osc_bridge/LTC_01000000_5mins_30_NDF_FPS_48000x16.wav b/tools/ltc_osc_bridge/LTC_01000000_5mins_30_NDF_FPS_48000x16.wav new file mode 100644 index 0000000000000000000000000000000000000000..aaa4a7564381adf90d427cd61aedee0e6229398a GIT binary patch literal 28800134 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 a{rw;R=^y_5m;d%Z{`k-T^S}J@r~d~)z#$s| literal 0 HcmV?d00001 diff --git a/tools/ltc_osc_bridge/Launch LTC Bridge.bat b/tools/ltc_osc_bridge/Launch LTC Bridge.bat new file mode 100644 index 0000000000..ee430f3f0c --- /dev/null +++ b/tools/ltc_osc_bridge/Launch LTC Bridge.bat @@ -0,0 +1,5 @@ +@echo off +cd /d "%~dp0" +python -m pip install -r requirements.txt --quiet +python ltc_osc_bridge_gui.py +pause diff --git a/tools/ltc_osc_bridge/Launch LTC Bridge.command b/tools/ltc_osc_bridge/Launch LTC Bridge.command new file mode 100755 index 0000000000..14f3e959c8 --- /dev/null +++ b/tools/ltc_osc_bridge/Launch LTC Bridge.command @@ -0,0 +1,6 @@ +#!/bin/bash +# LTC → OSC Bridge — double-click launcher (macOS) +# Make executable once: chmod +x "Launch LTC Bridge.command" +cd "$(dirname "$0")" +python3 -m pip install -r requirements.txt --quiet +python3 ltc_osc_bridge_gui.py diff --git a/tools/ltc_osc_bridge/OSC_BRIDGE_HANDOFF.md b/tools/ltc_osc_bridge/OSC_BRIDGE_HANDOFF.md new file mode 100644 index 0000000000..20aa84f091 --- /dev/null +++ b/tools/ltc_osc_bridge/OSC_BRIDGE_HANDOFF.md @@ -0,0 +1,233 @@ +# LTC → OSC Bridge — Agent Handoff + +**Task:** Build a small cross-platform Python app that listens for LTC (Linear Timecode) on a system audio input, decodes it, and sends the decoded timecode string via OSC to a dpx_tc001 pixel clock device (or any OSC receiver). + +**Status:** Not started. Directory created. No code exists yet. + +--- + +## What It Needs To Do + +1. List available audio input devices so user can pick the right one +2. Capture audio from a selected input channel (LTC arrives as audio — typically on one channel of a stereo or multi-channel interface) +3. Decode the LTC biphase mark signal in real time +4. Format the timecode as `HH:MM:SS:FF` (or `HH:MM:SS,FF` for drop frame) +5. Send via OSC UDP to a configurable target IP/port/address +6. Print current TC to terminal so user can confirm it's working + +--- + +## Target OSC Receiver (dpx_tc001 firmware) + +The receiving device is an ESP32 pixel clock running custom firmware. OSC is received on **UDP port 4210**. + +Relevant OSC addresses: + +| Address | Args | Effect | +|---------|------|--------| +| `/dpx_tc001/custom/tc` | `(s)` string | Creates/updates a **persistent custom app** named `tc` that stays in the display rotation — best for ongoing TC display | +| `/dpx_tc001/notify` | `(s)` string | **One-shot notification** — pops up, scrolls, disappears | +| `/notify` | `(s)` string | Same as above, no namespace prefix | + +**Recommendation:** Use `/dpx_tc001/custom/tc` as the default address. The custom app persists and updates live. The display name is "tc" and it will scroll the timecode string continuously. + +The device also accepts `/awtrix/custom/tc` as a compatibility alias. + +**OSC packet format:** Standard OSC 1.0 over UDP. No TCP, no bundles needed. + +--- + +## LTC Technical Spec + +**LTC = Linear Timecode (SMPTE 12M)** + +LTC encodes SMPTE timecode as an audio signal using **biphase mark code (BMC)**: +- The signal is an audio waveform — looks like a square wave with varying pulse widths +- Bit encoding: + - There is ALWAYS a transition at the start of every bit period + - Bit = **1**: additional transition at the MID-point of the bit period + - Bit = **0**: NO mid-point transition +- Result: measuring zero-crossing gaps: + - **Short gap** (≈ T/2): part of a '1' bit (two shorts in a row = one '1') + - **Long gap** (≈ T): a '0' bit + +**Frame structure (80 bits, transmitted LSB-first within each field):** + +``` +Bits 0- 3: Frame units (BCD, 0-9) +Bits 4- 7: User bits 1 (4 bits, ignore) +Bits 8- 9: Frame tens (BCD, 0-2) +Bit 10: Drop frame flag +Bit 11: Color frame flag +Bits 12-15: User bits 2 +Bits 16-19: Seconds units (BCD, 0-9) +Bits 20-23: User bits 3 +Bits 24-26: Seconds tens (BCD, 0-5) +Bit 27: Unused +Bits 28-31: User bits 4 +Bits 32-35: Minutes units (BCD, 0-9) +Bits 36-39: User bits 5 +Bits 40-42: Minutes tens (BCD, 0-5) +Bit 43: Biphase correction bit +Bits 44-47: User bits 6 +Bits 48-51: Hours units (BCD, 0-9) +Bits 52-55: User bits 7 +Bits 56-57: Hours tens (BCD, 0-2) +Bits 58-63: Flags + user bits 8 +Bits 64-79: SYNC WORD = 0011 1111 1111 1101 (fixed pattern, MSB first) +``` + +**Sync word check:** +```python +SYNC_WORD = [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1] # bits[64:80] +# or as integer (bit64=MSB): int(''.join(str(b) for b in bits[64:80]), 2) == 0x3FFD +``` + +**BCD decode helper:** +```python +def bcd(bits_slice): + return sum(b << i for i, b in enumerate(bits_slice)) +``` + +**Frame decode:** +```python +frames = bcd(bits[0:4]) + bcd(bits[8:10]) * 10 +drop = bool(bits[10]) +secs = bcd(bits[16:20]) + bcd(bits[24:27]) * 10 +mins = bcd(bits[32:36]) + bcd(bits[40:43]) * 10 +hours = bcd(bits[48:52]) + bcd(bits[56:58]) * 10 + +tc_str = f"{hours:02d}:{mins:02d}:{secs:02d}{',' if drop else ':'}{frames:02d}" +``` + +**Common frame rates:** 24, 25, 29.97 (DF), 30 fps. Bit rate = fps × 80 bits/frame. +At 30fps on 48kHz audio: T ≈ 1600 samples/bit, T/2 ≈ 800 samples. + +**Auto-detection of bit period:** Track recent zero-crossing gaps. The shortest gaps cluster around T/2. A simple approach: keep a running minimum of recent gaps (with outlier rejection) as the T/2 estimate. + +--- + +## Biphase Mark Decoder Algorithm + +``` +State machine with two states: IDLE and HALF + +On each zero crossing, measure gap since last crossing: + threshold = 1.5 × estimated_half_period + + If gap < threshold (SHORT): + If state == IDLE: → set state = HALF (first half of a '1') + If state == HALF: → emit bit=1, set state = IDLE + + If gap >= threshold (LONG): + If state == HALF: → resync error, reset state = IDLE + If state == IDLE: → emit bit=0, stay IDLE + +After emitting each bit, check last 80 bits for sync word. +When sync found at position P: decode bits[P:P+80] as frame, clear buffer. +``` + +**Auto-calibrate half period:** Use the median or filtered minimum of recent short gaps. Update continuously. Handle both short and long gaps gracefully — don't break on occasional noise. + +--- + +## Libraries + +``` +sounddevice # cross-platform audio I/O via PortAudio +numpy # signal processing +python-osc # OSC UDP client +``` + +``` +pip install sounddevice numpy python-osc +``` + +`sounddevice` uses PortAudio which ships pre-built for macOS/Windows/Linux — no system dependencies needed. + +--- + +## CLI Interface + +``` +python ltc_osc_bridge.py --list-devices +python ltc_osc_bridge.py --target 192.168.1.100 --device 2 +python ltc_osc_bridge.py --target 192.168.1.100 --device 2 --channel 1 --port 4210 +python ltc_osc_bridge.py --target 192.168.1.100 --device 2 --address /custom/tc +``` + +**Arguments:** +- `--list-devices` / `-l` — print available audio inputs and exit +- `--device` / `-d` — device index from list (default: system default input) +- `--channel` / `-c` — which channel index to read LTC from (default: 0) +- `--target` / `-t` — target IP (default: `192.168.1.100`) +- `--port` / `-p` — OSC port (default: `4210`) +- `--address` / `-a` — OSC address (default: `/dpx_tc001/custom/tc`) +- `--rate` / `-r` — sample rate in Hz (default: `48000`) + +--- + +## Output Format + +Terminal should show the current timecode updating in place: +``` +dpx_tc001 LTC→OSC Bridge + Target : 192.168.1.100:4210 + OSC : /dpx_tc001/custom/tc + Device : [2] Dante Virtual Soundcard + Channel: 0 + +Listening... Press Ctrl+C to stop + + TC: 01:23:45:12 ← updates in place on same line +``` + +--- + +## Edge Cases to Handle + +1. **No signal / silence** — don't spam OSC. Only send when a valid frame is decoded. +2. **Signal dropout** — after N frames with no valid decode, optionally send a blank or stop sending. +3. **Wrong channel** — user picks the wrong channel. Should fail gracefully with a useful message. +4. **Frame rate detection** — don't require user to specify fps. Auto-detect from bit period measurement. Display detected fps in the header. +5. **Rate limiting** — don't send OSC faster than once per frame (e.g., max 30 sends/sec). The display only updates ~30fps anyway. +6. **Drop frame** — format correctly with `;` or `,` separator when drop flag is set. + +--- + +## Files to Create + +``` +tools/ltc_osc_bridge/ + ltc_osc_bridge.py ← main script, single file, no classes required + requirements.txt ← sounddevice, numpy, python-osc +``` + +Keep it a single Python file. No packaging, no setup.py, no complexity. It should run with `python ltc_osc_bridge.py` after `pip install -r requirements.txt`. + +--- + +## Test Without LTC Hardware + +To test the OSC sending without an actual LTC signal, add a `--test` flag that sends a fake incrementing timecode at 30fps: + +```python +if args.test: + f = 0 + while True: + tc = f"{(f//108000)%24:02d}:{(f//1800)%60:02d}:{(f//30)%60:02d}:{f%30:02d}" + osc.send_message(args.address, tc) + print(f"\r TC: {tc} ", end="", flush=True) + f += 1 + time.sleep(1/30) +``` + +--- + +## Context + +- This tool is a companion to the `dpx_tc001` pixel clock firmware (ESP32, Ulanzi TC001) +- OSC receiver is on UDP port 4210, same port as device discovery — coexists fine +- The `/dpx_tc001/custom/tc` app will display the timecode string, scrolling it across the 32×8 LED matrix +- The firmware also accepts `/dpx_tc001/notify` for one-shot pop-up display +- Future: this same tool should work as-is with a WLED-based device that has an OSC receiver on the same port diff --git a/tools/ltc_osc_bridge/ltc_osc_bridge.py b/tools/ltc_osc_bridge/ltc_osc_bridge.py new file mode 100644 index 0000000000..91e78db46b --- /dev/null +++ b/tools/ltc_osc_bridge/ltc_osc_bridge.py @@ -0,0 +1,896 @@ +#!/usr/bin/env python3 +""" +ltc_osc_bridge — SMPTE LTC → OSC Bridge +========================================= +Decodes Linear Timecode (LTC/SMPTE 12M) from a system audio input or a WAV +file and sends the decoded timecode string via OSC UDP. + +Usage: + python ltc_osc_bridge.py --list-devices + python ltc_osc_bridge.py --target 192.168.1.100 --device 2 + python ltc_osc_bridge.py --wav test.wav --no-osc + python ltc_osc_bridge.py --test --target 192.168.1.100 + +Install deps: + pip install -r requirements.txt +""" + +from __future__ import annotations + +__version__ = "1.0.0" + +import argparse +import json +import sys +import time +import urllib.request +import urllib.error +import wave +import struct +import threading +from collections import deque +from typing import Callable, Optional, List + +import numpy as np + +# ── Optional deps (gracefully absent) ───────────────────────────────────────── + +try: + from pythonosc.udp_client import SimpleUDPClient as _UDPClient + _HAS_OSC = True +except ImportError: # pragma: no cover + _HAS_OSC = False + +try: + import sounddevice as sd + _HAS_SD = True +except ImportError: # pragma: no cover + _HAS_SD = False + +# ── LTC / SMPTE constants ────────────────────────────────────────────────────── + +# Sync word: bits 64-79 of each 80-bit LTC frame, transmitted MSB-first. +# Binary: 0011 1111 1111 1101 (0x3FFD) +_SYNC: tuple = (0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1) + +# Common SMPTE frame rates for FPS snap detection +_COMMON_FPS = (24.0, 25.0, 29.97, 30.0) + +# ── TC string ↔ frame-count helpers ─────────────────────────────────────────── + +def _tc_to_frames(tc: str, fps: float) -> int: + """Parse HH:MM:SS:FF (or with ;/,) into an absolute frame count.""" + parts = tc.strip().replace(";", ":").replace(",", ":").split(":") + if len(parts) != 4: + raise ValueError(f"Invalid timecode: {tc!r} (expected HH:MM:SS:FF)") + h, m, s, f = (int(x) for x in parts) + fps_r = round(fps) + return (h * 3600 + m * 60 + s) * fps_r + f + + +def _frames_to_tc(n: int, fps: float, drop: bool = False) -> str: + """Convert absolute frame count to HH:MM:SS:FF string.""" + fps_r = round(fps) + fr = n % fps_r + ts = n // fps_r + s = ts % 60 + tm = ts // 60 + m = tm % 60 + h = tm // 60 + sep = ";" if drop else ":" + return f"{h:02d}:{m:02d}:{s:02d}{sep}{fr:02d}" + + +# ── BCD helpers ──────────────────────────────────────────────────────────────── + +def _bcd(bits: List[int], start: int, length: int) -> int: + """Decode BCD integer from LSB-first bit slice.""" + return sum(bits[start + i] << i for i in range(length)) + + +def _decode_frame(bits: List[int]) -> Optional[tuple]: + """ + Decode one 80-bit LTC frame. + Returns (tc_str, drop_frame) or None if invalid. + """ + if tuple(bits[64:80]) != _SYNC: + return None + fr = _bcd(bits, 0, 4) + _bcd(bits, 8, 2) * 10 + df = bool(bits[10]) + sc = _bcd(bits, 16, 4) + _bcd(bits, 24, 3) * 10 + mn = _bcd(bits, 32, 4) + _bcd(bits, 40, 3) * 10 + hr = _bcd(bits, 48, 4) + _bcd(bits, 56, 2) * 10 + # Sanity-check values + if fr > 29 or sc > 59 or mn > 59 or hr > 23: + return None + sep = ";" if df else ":" + return f"{hr:02d}:{mn:02d}:{sc:02d}{sep}{fr:02d}", df + +# ── LTC Decoder ──────────────────────────────────────────────────────────────── + +class LTCDecoder: + """ + Streaming biphase-mark LTC decoder. + + Feed mono float32 audio via .feed(). Each decoded frame is delivered to + the on_frame(tc_str: str, drop_frame: bool, fps: float | None) callback + from the calling thread. + + Thread-safety: not thread-safe by itself; use a single producer thread. + """ + + #: Number of zero-crossing gaps to collect before bootstrapping half-period. + #: 300 gaps ≈ 2+ full LTC frames, guaranteeing we capture the sync word's + #: 26 short gaps even in worst-case (mostly-zero timecode) data. + _BOOT_N: int = 300 + + #: EMA alpha for adaptive half-period tracking (smaller = slower/stabler). + _HP_ALPHA: float = 0.08 + + #: Maximum search window when hunting for sync (bits). Larger = more robust + #: initial lock, slightly more CPU when misaligned. + _SYNC_SEARCH_WINDOW: int = 32 + + def __init__(self, sample_rate: int = 48000, + on_frame: Optional[Callable] = None) -> None: + self.sample_rate = sample_rate + self.on_frame = on_frame or (lambda *_: None) + + # Adaptive half-period estimator (samples per half-bit-period) + self._hp: float = 0.0 + self._boot_gaps: List[float] = [] + + # Biphase-mark state machine: 0=IDLE, 1=HALF + self._bmc_state: int = 0 + + # Bit accumulator (plain list for fast appends + slicing) + self._buf: List[int] = [] + + # Absolute sample position of the last detected zero-crossing + self._last_cross: int = -1 + + # Sign of the last sample from the previous feed() call. + # Used to detect zero-crossings at chunk boundaries. + self._last_sign: int = 0 + + # Total samples consumed (used for FPS timing) + self._n: int = 0 + + # FPS estimation (ring buffer of frame arrival times in samples) + self._frame_times: deque = deque(maxlen=12) + + # Absolute position of the most-recently processed crossing. + # Updated in feed() before each _process_gap() call so that + # _record_frame() can use a precise timestamp instead of self._n. + self._cur_abs_pos: int = 0 + + # Public stats + self.fps: Optional[float] = None + self.frame_count: int = 0 + + # ── Half-period estimation ───────────────────────────────────────────────── + + def _bootstrap_hp(self) -> None: + """ + Bootstrap half-period from initial gap collection. + + Gaps form two clusters: short (≈T/2) and long (≈T = 2×T/2). + We find the minimum observed gap (≈T/2) and treat everything within + 60% of that as the short cluster, then take the median. + + This correctly handles worst-case LTC content (mostly-zero timecodes) + where short gaps may be a minority of the bootstrap window. + """ + arr = sorted(g for g in self._boot_gaps if g > 3) + if not arr: + return + # The minimum gap is T/2 (or very close). T = 2×T/2 so the two + # clusters are well-separated: short < 1.6×min, long ≈ 2×min. + min_g = arr[0] + shorts = [g for g in arr if g <= min_g * 1.6] + self._hp = float(np.median(shorts)) if shorts else float(min_g) + self._boot_gaps = [] + + def _update_hp(self, short_gap: float) -> None: + """Exponential moving-average update with a measured short gap.""" + self._hp = (1.0 - self._HP_ALPHA) * self._hp + self._HP_ALPHA * short_gap + + # ── Bit / frame processing ───────────────────────────────────────────────── + + def _push_bit(self, b: int) -> None: + self._buf.append(b) + if len(self._buf) >= 80: + self._search_sync() + + def _search_sync(self) -> None: + """ + Search the bit buffer for a valid LTC frame. + Scans up to _SYNC_SEARCH_WINDOW positions from the oldest end to + lock on quickly while staying O(1) in the steady state. + """ + buf = self._buf + blen = len(buf) + limit = blen - 79 # number of possible frame start positions + + # In steady state (aligned), the frame starts at position 0. + # We allow a small window for cases where a few extra bits accumulated + # before the previous decode (noise, startup misalignment). + for i in range(min(limit, self._SYNC_SEARCH_WINDOW)): + if tuple(buf[i + 64 : i + 80]) == _SYNC: + result = _decode_frame(buf[i : i + 80]) + if result is not None: + tc, df = result + self._on_valid_frame(tc, df) + del buf[: i + 80] + return + + # No sync found in search window; trim to keep last 79 bits so the + # next incoming bit can complete a frame without carrying stale data. + if blen > 200: + del buf[:-79] + + def _on_valid_frame(self, tc: str, df: bool) -> None: + self.frame_count += 1 + self._frame_times.append(self._cur_abs_pos) # precise crossing position + self._estimate_fps() + self.on_frame(tc, df, self.fps) + + def _estimate_fps(self) -> None: + ft = self._frame_times + if len(ft) < 3: + return + intervals = [ft[k] - ft[k - 1] for k in range(1, len(ft))] + avg = float(np.mean(intervals)) + if avg <= 0: + return + raw = self.sample_rate / avg + best = min(_COMMON_FPS, key=lambda f: abs(raw - f)) + if abs(raw - best) < 1.5: + self.fps = best + + # ── Gap / BMC logic ──────────────────────────────────────────────────────── + + def _process_gap(self, gap: int) -> None: + """Handle one measured inter-crossing gap (in samples).""" + # ── Bootstrapping ────────────────────────────────────────────────────── + if self._hp == 0.0: + if 2 < gap < 8000: + self._boot_gaps.append(gap) + if len(self._boot_gaps) >= self._BOOT_N: + self._bootstrap_hp() + return + + # ── Classify gap ─────────────────────────────────────────────────────── + threshold = self._hp * 1.5 # boundary between T/2 and T + + if gap < threshold: + # ── Short gap (≈ T/2): part of a '1' bit ────────────────────────── + self._update_hp(gap) + if self._bmc_state == 0: # IDLE → HALF (first half of '1') + self._bmc_state = 1 + else: # HALF → emit '1', back to IDLE + self._push_bit(1) + self._bmc_state = 0 + + elif gap < threshold * 2.5: + # ── Long gap (≈ T): a '0' bit ───────────────────────────────────── + if self._bmc_state == 1: # unexpected long after half → resync + self._bmc_state = 0 + else: + self._push_bit(0) + + else: + # ── Very long gap: dropout / silence ────────────────────────────── + self._bmc_state = 0 + + # ── Public interface ─────────────────────────────────────────────────────── + + def feed(self, samples: np.ndarray) -> None: + """ + Process a 1-D float32 mono numpy array. + May be called from an audio callback or any single thread. + """ + if samples.ndim != 1: + raise ValueError("LTCDecoder.feed() expects a 1-D mono array") + + # Sign array: +1 / -1; treat exact-zero samples as positive (rare in + # real audio; a 1-sample timing offset at T/2=10 samples is harmless). + signs = np.sign(samples).astype(np.int8) + signs[signs == 0] = 1 + + # ── Boundary crossing detection ────────────────────────────────────── + # np.diff() cannot see across successive feed() calls. If the LTC + # signal has a zero-crossing exactly at the chunk boundary (i.e., the + # last sample of the previous call and the first sample of this call + # have opposite signs), we must detect it here explicitly. + if self._last_sign != 0 and signs[0] != self._last_sign: + abs_pos = self._n # first sample of this chunk = boundary position + self._cur_abs_pos = abs_pos + if self._last_cross < 0: + self._last_cross = abs_pos + else: + self._process_gap(abs_pos - self._last_cross) + self._last_cross = abs_pos + + # Store last sign before we overwrite it below + self._last_sign = int(signs[-1]) + + # ── Internal zero-crossings ────────────────────────────────────────── + crossings = np.where(np.diff(signs) != 0)[0] + for idx in crossings: + abs_pos = self._n + int(idx) + 1 + self._cur_abs_pos = abs_pos + if self._last_cross < 0: + self._last_cross = abs_pos + else: + self._process_gap(abs_pos - self._last_cross) + self._last_cross = abs_pos + + self._n += len(samples) + + def reset(self) -> None: + """Reset all decoder state (e.g., after detected signal loss).""" + self._hp = 0.0 + self._boot_gaps = [] + self._bmc_state = 0 + self._buf = [] + self._last_cross = -1 + self._last_sign = 0 + self.fps = None + +# ── OSC sender ───────────────────────────────────────────────────────────────── + +class OSCSender: + """Thread-safe OSC UDP sender with frame-rate limiting.""" + + def __init__(self, host: str, port: int, address: str) -> None: + if not _HAS_OSC: + raise RuntimeError( + "python-osc not installed. Run: pip install python-osc" + ) + self._client = _UDPClient(host, port) + self._address = address + self._lock = threading.Lock() + self._last_sent: float = 0.0 + self._min_interval: float = 1.0 / 32 # ≤ 32 sends / sec + + def send(self, tc_str: str) -> None: + now = time.monotonic() + with self._lock: + if now - self._last_sent < self._min_interval: + return + self._last_sent = now + try: + self._client.send_message(self._address, tc_str) + except OSError: + pass # network unreachable — don't crash the audio thread + +# ── Device listing ───────────────────────────────────────────────────────────── + +def list_devices() -> None: + if not _HAS_SD: + _die("sounddevice not installed. Run: pip install sounddevice") + devices = sd.query_devices() + print("\nAvailable audio input devices:\n") + for i, dev in enumerate(devices): + if dev["max_input_channels"] < 1: + continue + sr = int(dev["default_samplerate"]) + ch = dev["max_input_channels"] + print(f" [{i:3d}] {dev['name']}") + print(f" {ch} in · {sr} Hz default") + print() + +# ── WAV file mode ────────────────────────────────────────────────────────────── + +def run_wav(path: str, args: argparse.Namespace, + osc: Optional[OSCSender]) -> None: + """Decode LTC from a WAV file and optionally send via OSC.""" + try: + wf = wave.open(path, "rb") + except FileNotFoundError: + _die(f"WAV file not found: {path}") + except wave.Error as e: + _die(f"Cannot open WAV file: {e}") + + n_ch = wf.getnchannels() + sampw = wf.getsampwidth() + rate = wf.getframerate() + n_samp = wf.getnframes() + dur = n_samp / rate + + if args.channel >= n_ch: + _die(f"WAV has {n_ch} channel(s); --channel {args.channel} is out of range.") + + dtype_map = {1: np.int8, 2: np.int16, 4: np.int32} + if sampw not in dtype_map: + _die(f"Unsupported WAV sample width: {sampw} bytes") + + dtype = dtype_map[sampw] + max_val = float(2 ** (sampw * 8 - 1)) + + print(f"\n File : {path}") + print(f" Rate : {rate} Hz · {n_ch}ch · {sampw*8}-bit · {dur:.1f} s") + print(f" Channel: {args.channel}") + if osc: + print(f" OSC : {args.target}:{args.port} {args.address}") + print() + + last_tc: list = [None] + unique_count: list = [0] + start_time = time.monotonic() + + def on_frame(tc: str, df: bool, fps: Optional[float]) -> None: + if tc != last_tc[0]: + last_tc[0] = tc + unique_count[0] += 1 + fps_str = f" @{fps:.2f} fps" if fps else "" + print(f"\r TC: {tc}{fps_str} ", end="", flush=True) + if osc: + osc.send(tc) + + dec = LTCDecoder(sample_rate=rate, on_frame=on_frame) + + CHUNK = 4096 + try: + while True: + raw = wf.readframes(CHUNK) + if not raw: + break + interleaved = np.frombuffer(raw, dtype=dtype) + # De-interleave: select the chosen channel + mono = interleaved[args.channel::n_ch].astype(np.float32) / max_val + dec.feed(mono) + except KeyboardInterrupt: + pass + finally: + wf.close() + + elapsed = time.monotonic() - start_time + print(f"\n\n Done in {elapsed:.1f}s. " + f"{unique_count[0]} unique timecodes decoded, " + f"{dec.frame_count} frames total.") + if dec.fps: + print(f" Detected FPS: {dec.fps}") + +# ── Direct OSC send mode + d3 showcontrol ───────────────────────────────────── + +# disguise d3 zero-argument trigger paths +_D3_TRIGGERS: dict = { + "d3_play": "/d3/showcontrol/play", + "d3_stop": "/d3/showcontrol/stop", + "d3_loop": "/d3/showcontrol/loop", + "d3_playsection": "/d3/showcontrol/playsection", + "d3_nextsection": "/d3/showcontrol/nextsection", + "d3_previoussection": "/d3/showcontrol/previoussection", + "d3_nexttrack": "/d3/showcontrol/nexttrack", + "d3_previoustrack": "/d3/showcontrol/previoustrack", + "d3_returntostart": "/d3/showcontrol/returntostart", + "d3_hold": "/d3/showcontrol/hold", + "d3_fadeup": "/d3/showcontrol/fadeup", + "d3_fadedown": "/d3/showcontrol/fadedown", +} +_D3_VALUES = ("d3_volume", "d3_brightness", "d3_trackname", "d3_trackid", + "d3_cue", "d3_floatcue") + +# disguise d3 monitoring output paths (§7.3) — sent FROM d3 TO device +# Tuple: (osc_path, suggested_channel, label) +_D3_MONITORING: dict = { + "timecodeposition": ("/d3/showcontrol/timecodeposition", "tc", "Timecode"), + "trackposition": ("/d3/showcontrol/trackposition", "d3_pos", "Track Position"), + "trackname": ("/d3/showcontrol/trackname", "d3_name", "Track Name"), + "trackid": ("/d3/showcontrol/trackid", "d3_id", "Track ID"), + "playmode": ("/d3/showcontrol/playmode", "d3_mode", "Play Mode"), + "currentsectionname": ("/d3/showcontrol/currentsectionname","d3_sec", "Current Section"), + "nextsectionname": ("/d3/showcontrol/nextsectionname", "d3_nsec", "Next Section"), + "sectionhint": ("/d3/showcontrol/sectionhint", "d3_hint", "Section Hint"), + "volume": ("/d3/showcontrol/volume", "d3_vol", "Volume"), + "brightness": ("/d3/showcontrol/brightness", "d3_bri", "Brightness"), + "bpm": ("/d3/showcontrol/bpm", "d3_bpm", "BPM"), + "heartbeat": ("/d3/showcontrol/heartbeat", "d3_hb", "Heartbeat"), +} + + +def _any_d3(args: argparse.Namespace) -> bool: + return (any(getattr(args, k, False) for k in _D3_TRIGGERS) or + any(getattr(args, k, None) is not None for k in _D3_VALUES)) + + +def run_d3(args: argparse.Namespace) -> None: + """Send a disguise Designer showcontrol OSC command and exit.""" + if not _HAS_OSC: + _die("python-osc not installed. Run: pip install python-osc") + from pythonosc.udp_client import SimpleUDPClient + client = SimpleUDPClient(args.target, args.d3_port) + + def _send(path: str, value=None) -> None: + client.send_message(path, value) + val_str = f" {value!r}" if value is not None else "" + print(f" d3 → {args.target}:{args.d3_port}") + print(f" {path}{val_str}") + + # Zero-argument triggers + for dest, path in _D3_TRIGGERS.items(): + if getattr(args, dest, False): + _send(path) + return + + # Value commands + if args.d3_volume is not None: + _send("/d3/showcontrol/volume", max(0.0, min(1.0, float(args.d3_volume)))) + elif args.d3_brightness is not None: + _send("/d3/showcontrol/brightness", max(0.0, min(1.0, float(args.d3_brightness)))) + elif args.d3_trackname is not None: + _send("/d3/showcontrol/trackname", args.d3_trackname) + elif args.d3_trackid is not None: + _send("/d3/showcontrol/trackid", args.d3_trackid) + elif args.d3_cue is not None: + ints = [int(x) for x in args.d3_cue[:3]] + client.send_message("/d3/showcontrol/cue", ints[0] if len(ints) == 1 else ints) + print(f" d3 → {args.target}:{args.d3_port}") + print(f" /d3/showcontrol/cue {'.' .join(str(i) for i in ints)}") + elif args.d3_floatcue is not None: + _send("/d3/showcontrol/floatcue", float(args.d3_floatcue)) + else: + _die("No d3 command given — use --d3-play, --d3-volume, etc. (--help)") + + +# ── d3 monitoring listener registry (HTTP) ──────────────────────────────────── + +def _listener_api(args: argparse.Namespace, method: str, body: Optional[dict] = None) -> str: + """Call the device's /api/osc/listeners HTTP endpoint.""" + url = f"http://{args.target}:{args.http_port}/api/osc/listeners" + data = json.dumps(body).encode() if body is not None else None + req = urllib.request.Request( + url, data=data, + headers={"Content-Type": "application/json"} if data else {}, + method=method, + ) + try: + with urllib.request.urlopen(req, timeout=5) as resp: + return resp.read().decode() + except urllib.error.URLError as exc: + _die(f"Device HTTP error ({url}): {exc.reason}") + return "" + + +def run_listener_cmds(args: argparse.Namespace) -> None: + """Handle --d3-list-listeners / --d3-add-listener / --d3-remove-listener / --d3-preset.""" + prefix = f" device → http://{args.target}:{args.http_port}" + + if args.d3_list_listeners: + raw = _listener_api(args, "GET") + listeners: list = json.loads(raw) if raw else [] + if not listeners: + print(f"{prefix}\n No listeners registered.") + else: + print(f"{prefix}") + print(f" {'OSC Path':<47} {'Channel':<15} Label") + print(" " + "─" * 76) + for lsr in listeners: + print(f" {lsr['path']:<47} {lsr['channel']:<15} {lsr.get('label','')}") + return + + if args.d3_add_listener: + parts = args.d3_add_listener + if len(parts) < 2: + _die("--d3-add-listener requires PATH CHANNEL [LABEL]") + path, channel = parts[0], parts[1] + label = parts[2] if len(parts) > 2 else channel + _listener_api(args, "POST", {"path": path, "channel": channel, "label": label}) + print(f"{prefix}\n Added : {path} → {channel} ({label})") + return + + if args.d3_remove_listener: + _listener_api(args, "DELETE", {"path": args.d3_remove_listener}) + print(f"{prefix}\n Removed : {args.d3_remove_listener}") + return + + if args.d3_preset: + if args.d3_preset == "all": + items = list(_D3_MONITORING.values()) + elif args.d3_preset in _D3_MONITORING: + items = [_D3_MONITORING[args.d3_preset]] + else: + names = ", ".join(_D3_MONITORING.keys()) + _die(f"Unknown preset '{args.d3_preset}'. Choose: all, {names}") + print(f"{prefix}") + for path, channel, label in items: + _listener_api(args, "POST", {"path": path, "channel": channel, "label": label}) + print(f" Registered: {path} → {channel} ({label})") + return + + +def _any_listener_cmd(args: argparse.Namespace) -> bool: + return any([ + getattr(args, "d3_list_listeners", False), + getattr(args, "d3_add_listener", None) is not None, + getattr(args, "d3_remove_listener",None) is not None, + getattr(args, "d3_preset", None) is not None, + ]) + + +def run_send(args: argparse.Namespace, osc: Optional["OSCSender"]) -> None: + """Send a single OSC string immediately and exit.""" + if osc is None: + _die("--send requires OSC output. Don't use --no-osc with --send.") + msg = args.send + # Bypass rate-limiting: send directly for one-shot use + try: + osc._client.send_message(args.address, msg) # type: ignore[union-attr] + print(f" Sent : {args.address}") + print(f" Value : \"{msg}\"") + print(f" To : {args.target}:{args.port}") + except OSError as exc: + _die(f"OSC send failed: {exc}") + + +# ── Test / generate mode ────────────────────────────────────────────────────── + +def run_test(args: argparse.Namespace, osc: Optional[OSCSender]) -> None: + """Generate and send TC from an arbitrary start time at a given frame rate.""" + fps = float(getattr(args, "fps", 30.0)) + start_tc_str = getattr(args, "start_tc", None) + try: + start = _tc_to_frames(start_tc_str, fps) if start_tc_str else 0 + except ValueError as exc: + _die(str(exc)) + print(f"\n [GENERATE] {fps} fps from {_frames_to_tc(start, fps)}. Ctrl+C to stop.\n") + f = start + try: + while True: + tc = _frames_to_tc(f, fps) + print(f"\r TC: {tc} ", end="", flush=True) + if osc: + osc.send(tc) + f += 1 + time.sleep(1.0 / fps) + except KeyboardInterrupt: + print("\n\n Stopped.") + +# ── Live audio mode ──────────────────────────────────────────────────────────── + +def run_live(args: argparse.Namespace, osc: Optional[OSCSender]) -> None: + if not _HAS_SD: + _die("sounddevice not installed. Run: pip install sounddevice") + + # Resolve device + try: + dev_idx = args.device # None = system default + dev_info = sd.query_devices(dev_idx, "input") + except Exception as exc: + _die(f"Cannot open audio device: {exc}") + + n_ch = int(dev_info["max_input_channels"]) + if args.channel >= n_ch: + _die(f"Device has {n_ch} input channel(s); --channel {args.channel} is out of range.") + + rate = args.rate or int(dev_info["default_samplerate"]) + name = dev_info["name"] + + print(f"\n Target : {args.target}:{args.port}") + print(f" OSC : {args.address}") + if dev_idx is not None: + print(f" Device : [{dev_idx}] {name}") + else: + print(f" Device : [default] {name}") + print(f" Channel: {args.channel}") + print(f" Rate : {rate} Hz") + print("\n Listening... Ctrl+C to stop\n") + + last_tc: list = [None] + dec = LTCDecoder(sample_rate=rate, on_frame=lambda *_: None) + + def on_frame(tc: str, df: bool, fps: Optional[float]) -> None: + if tc != last_tc[0]: + last_tc[0] = tc + fps_str = f" @{fps:.2f}" if fps else "" + print(f"\r TC: {tc}{fps_str} ", end="", flush=True) + if osc: + osc.send(tc) + + dec.on_frame = on_frame # type: ignore[assignment] + + def audio_callback(indata: np.ndarray, frames: int, + time_info: object, status: object) -> None: + if status: + print(f"\n [audio] {status}", file=sys.stderr) + mono = indata[:, args.channel].copy() + dec.feed(mono) + + try: + with sd.InputStream( + device = dev_idx, + channels = n_ch, + samplerate = rate, + dtype = "float32", + blocksize = 1024, + callback = audio_callback, + ): + while True: + time.sleep(0.1) + except KeyboardInterrupt: + print("\n\n Stopped.") + except sd.PortAudioError as exc: + _die(f"PortAudio error: {exc}") + except Exception as exc: + _die(f"Audio error: {exc}") + +# ── Argument parser ──────────────────────────────────────────────────────────── + +def _build_parser() -> argparse.ArgumentParser: + p = argparse.ArgumentParser( + prog="ltc_osc_bridge", + description=( + "Decode SMPTE LTC from a system audio input (or WAV file) " + "and send the timecode via OSC UDP." + ), + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +LTC → OSC examples: + %(prog)s --list-devices + %(prog)s --target 192.168.1.100 --device 2 + %(prog)s --wav ltc.wav --no-osc + %(prog)s --test --start-tc 01:00:00:00 --fps 25 --target 192.168.1.100 + %(prog)s --send "01:00:00:00" --target 192.168.1.100 --address /dpx_tc001/notify + +disguise d3 showcontrol examples: + %(prog)s --target 192.168.1.200 --d3-play + %(prog)s --target 192.168.1.200 --d3-stop + %(prog)s --target 192.168.1.200 --d3-cue 1 2 5 + %(prog)s --target 192.168.1.200 --d3-volume 0.8 + %(prog)s --target 192.168.1.200 --d3-brightness 0.5 + %(prog)s --target 192.168.1.200 --d3-trackname "Act 2" + +d3 monitoring listener registry examples: + %(prog)s --target 192.168.1.100 --d3-list-listeners + %(prog)s --target 192.168.1.100 --d3-preset all + %(prog)s --target 192.168.1.100 --d3-preset timecodeposition + %(prog)s --target 192.168.1.100 --d3-add-listener /d3/showcontrol/playmode d3_mode "Play Mode" + %(prog)s --target 192.168.1.100 --d3-remove-listener /d3/showcontrol/heartbeat +""", + ) + p.add_argument("-l", "--list-devices", action="store_true", + help="List available audio input devices and exit") + p.add_argument("-d", "--device", type=int, default=None, metavar="INDEX", + help="Audio input device index (default: system default)") + p.add_argument("-c", "--channel", type=int, default=0, metavar="N", + help="Audio channel index to read LTC from (default: 0)") + p.add_argument("-t", "--target", default="192.168.1.100", metavar="IP", + help="OSC target IP address (default: 192.168.1.100)") + p.add_argument("-p", "--port", type=int, default=4210, metavar="PORT", + help="OSC UDP port (default: 4210)") + p.add_argument("-a", "--address", default="/dpx_tc001/custom/tc", + metavar="ADDR", + help="OSC address (default: /dpx_tc001/custom/tc)") + p.add_argument("-r", "--rate", type=int, default=None, metavar="HZ", + help="Sample rate in Hz (default: device default)") + p.add_argument("--wav", metavar="FILE", + help="Decode LTC from a WAV file instead of live audio") + p.add_argument("--send", metavar="STRING", + help="Send a single OSC string to --address and exit") + p.add_argument("--no-osc", action="store_true", + help="Disable OSC output (decode and print only)") + p.add_argument("--test", action="store_true", + help="Generate TC from --start-tc at --fps (no audio needed)") + p.add_argument("--start-tc", default=None, metavar="HH:MM:SS:FF", + help="Starting timecode for generate mode (default: 00:00:00:00)") + p.add_argument("--fps", type=float, default=30.0, metavar="FPS", + help="Frame rate for generate mode: 24 / 25 / 29.97 / 30 (default: 30)") + p.add_argument("--version", action="version", + version=f"%(prog)s {__version__}") + + # ── disguise d3 showcontrol ──────────────────────────────────────────────── + d3g = p.add_argument_group( + "disguise d3 showcontrol", + "Send OSC transport commands to a disguise Designer machine and exit." + ) + d3g.add_argument("--d3-port", type=int, default=7401, metavar="PORT", + help="disguise OSC receive port (default: 7401)") + # Trigger commands (no args) + for _flag, _path in [ + ("--d3-play", "play"), + ("--d3-stop", "stop"), + ("--d3-loop", "loop section"), + ("--d3-playsection", "play to end of section"), + ("--d3-nextsection", "jump next section"), + ("--d3-previoussection", "jump previous section"), + ("--d3-nexttrack", "jump next track"), + ("--d3-previoustrack", "jump previous track"), + ("--d3-returntostart", "return to start"), + ("--d3-hold", "hold/freeze outputs"), + ("--d3-fadeup", "master fade up"), + ("--d3-fadedown", "master fade down"), + ]: + d3g.add_argument(_flag, action="store_true", help=f"/d3/showcontrol/{_path}") + # Value commands + d3g.add_argument("--d3-volume", type=float, metavar="0-1", + help="Set master volume (float 0.0–1.0)") + d3g.add_argument("--d3-brightness", type=float, metavar="0-1", + help="Set master brightness (float 0.0–1.0)") + d3g.add_argument("--d3-trackname", metavar="NAME", + help="Jump to named track (string)") + d3g.add_argument("--d3-trackid", metavar="ID", + help="Jump to track by ID (string/int)") + d3g.add_argument("--d3-cue", nargs="+", metavar="N", + help="Trigger cue e.g. --d3-cue 1 2 5 → cue 1.2.5") + d3g.add_argument("--d3-floatcue", type=float, metavar="FLOAT", + help="Trigger float cue (single float, e.g. 1.05)") + + # ── d3 monitoring listener registry (device HTTP API) ───────────────────── + _preset_names = ", ".join(_D3_MONITORING.keys()) + d3m = p.add_argument_group( + "d3 monitoring listener registry", + "Manage which d3 OSC monitoring paths the device listens for.\n" + "These paths are broadcast FROM disguise TO the device (§7.3).\n" + "Uses the device HTTP API — --target must be the device IP." + ) + d3m.add_argument("--http-port", type=int, default=80, metavar="PORT", + help="Device HTTP port (default: 80)") + d3m.add_argument("--d3-list-listeners", action="store_true", + help="List listener registry stored on device") + d3m.add_argument("--d3-add-listener", nargs="+", metavar=("PATH", "CHANNEL"), + help="Add listener: PATH CHANNEL [LABEL]") + d3m.add_argument("--d3-remove-listener", metavar="PATH", + help="Remove listener by OSC path") + d3m.add_argument("--d3-preset", metavar="NAME", + help=f"Register well-known preset(s) on device: all, or one of: {_preset_names}") + return p + +# ── Helpers ──────────────────────────────────────────────────────────────────── + +def _die(msg: str, code: int = 1) -> None: + print(f"ERROR: {msg}", file=sys.stderr) + sys.exit(code) + +# ── Entry point ──────────────────────────────────────────────────────────────── + +def main() -> None: + p = _build_parser() + args = p.parse_args() + + print(f"\ndpx_tc001 LTC → OSC Bridge v{__version__}") + print("─" * 44) + + if args.list_devices: + list_devices() + return + + # Set up OSC sender (unless suppressed) + osc: Optional[OSCSender] = None + if not args.no_osc: + if not _HAS_OSC: + print( + "WARNING: python-osc not installed — OSC output disabled.\n" + " pip install python-osc\n", + file=sys.stderr, + ) + else: + try: + osc = OSCSender(args.target, args.port, args.address) + print(f" OSC → udp://{args.target}:{args.port} {args.address}") + except Exception as exc: + print(f"WARNING: Could not init OSC sender: {exc}", file=sys.stderr) + + # d3 showcontrol: no OSC sender needed (uses own client directly) + if _any_d3(args): + run_d3(args) + return + + # d3 monitoring listener registry management (device HTTP API) + if _any_listener_cmd(args): + run_listener_cmds(args) + return + + if args.send is not None: + run_send(args, osc) + elif args.test: + run_test(args, osc) + elif args.wav: + run_wav(args.wav, args, osc) + else: + run_live(args, osc) + + +if __name__ == "__main__": + main() diff --git a/tools/ltc_osc_bridge/ltc_osc_bridge_gui.py b/tools/ltc_osc_bridge/ltc_osc_bridge_gui.py new file mode 100644 index 0000000000..fc258dcbf8 --- /dev/null +++ b/tools/ltc_osc_bridge/ltc_osc_bridge_gui.py @@ -0,0 +1,1155 @@ +#!/usr/bin/env python3 +""" +LTC → OSC Bridge — Web GUI v2.0 +================================== +Two-tab web interface: + Tab 1: LTC → OSC — live audio decode | TC generator | WAV file playback + Tab 2: d3 Control — disguise Designer showcontrol OSC panel + +Opens http://localhost:8765 automatically. +Usage: + python ltc_osc_bridge_gui.py + python ltc_osc_bridge_gui.py --port 9000 +""" + +from __future__ import annotations + +import json +import os +import queue +import sys +import tempfile +import threading +import time +import wave +import webbrowser +from typing import Optional + +# ── Dep checks ───────────────────────────────────────────────────────────────── + +def _die(msg: str) -> None: + print(f"ERROR: {msg}", file=sys.stderr) + sys.exit(1) + +try: + from flask import Flask, Response, jsonify, request, stream_with_context +except ImportError: + _die("Flask not installed.\n Run: pip install flask") + +try: + import numpy as np +except ImportError: + _die("NumPy not installed.\n Run: pip install numpy") + +try: + from ltc_osc_bridge import ( + LTCDecoder, OSCSender, _tc_to_frames, _frames_to_tc, + _HAS_SD, _HAS_OSC, + ) +except ImportError: + _die("ltc_osc_bridge.py not found in the same directory.") + +if _HAS_SD: + import sounddevice as sd + +if _HAS_OSC: + from pythonosc.udp_client import SimpleUDPClient as _UDPClient + +# ── Flask app ─────────────────────────────────────────────────────────────────── + +app = Flask(__name__) +app.config["SECRET_KEY"] = "ltc-osc-bridge-gui-v2-local" + +# ── Shared state ──────────────────────────────────────────────────────────────── + +_lock = threading.Lock() +_subscribers: list[queue.Queue] = [] + +_running = False +_audio_stream = None # sounddevice InputStream (live mode) +_bg_thread = None # Thread (generate / wav mode) +_decoder = None # LTCDecoder +_osc_sender = None # OSCSender +_wav_tmp_path = None # path to uploaded WAV file +_stats = {"tc": "--:--:--:--", "fps": None, "frames": 0} + + +def _broadcast(payload: dict) -> None: + msg = json.dumps(payload) + with _lock: + dead = [] + for q in _subscribers: + try: + q.put_nowait(msg) + except queue.Full: + dead.append(q) + for q in dead: + _subscribers.remove(q) + + +def _make_on_frame(osc): + """Return an on_frame callback that broadcasts TC and optionally sends OSC.""" + def on_frame(tc: str, df: bool, fps) -> None: + _stats["tc"] = tc + _stats["fps"] = fps + _stats["frames"] = _stats["frames"] + 1 + _broadcast({"tc": tc, "fps": fps, "frames": _stats["frames"]}) + if osc: + osc.send(tc) + return on_frame + + +# ── Background threads ────────────────────────────────────────────────────────── + +def _thread_generate(start_frame: int, fps: float, osc) -> None: + global _running + on_frame = _make_on_frame(osc) + f = start_frame + interval = 1.0 / fps + try: + while _running: + on_frame(_frames_to_tc(f, fps), False, fps) + f += 1 + time.sleep(interval) + except Exception as exc: + _broadcast({"error": str(exc)}) + _running = False + _broadcast({"stopped": True}) + + +def _thread_wav(path: str, channel: int, osc) -> None: + global _running + try: + wf = wave.open(path, "rb") + n_ch = wf.getnchannels() + sampw = wf.getsampwidth() + rate = wf.getframerate() + + dtype_map = {1: np.int8, 2: np.int16, 4: np.int32} + if sampw not in dtype_map or channel >= n_ch: + _broadcast({"error": f"WAV: bad format or channel out of range (has {n_ch}ch)"}) + _running = False + return + + dtype = dtype_map[sampw] + max_val = float(2 ** (sampw * 8 - 1)) + dec = LTCDecoder(sample_rate=rate, on_frame=_make_on_frame(osc)) + + CHUNK = 4096 + chunk_dur = CHUNK / rate # seconds per chunk (for real-time pacing) + + while _running: + raw = wf.readframes(CHUNK) + if not raw: + break + t0 = time.monotonic() + interleaved = np.frombuffer(raw, dtype=dtype) + mono = interleaved[channel::n_ch].astype(np.float32) / max_val + dec.feed(mono) + sleep = chunk_dur - (time.monotonic() - t0) + if sleep > 0: + time.sleep(sleep) + + wf.close() + except Exception as exc: + _broadcast({"error": str(exc)}) + _running = False + _broadcast({"stopped": True, "reason": "WAV playback complete"}) + + +# ── Routes ────────────────────────────────────────────────────────────────────── + +@app.route("/") +def index(): + return _HTML, 200, {"Content-Type": "text/html; charset=utf-8"} + + +@app.route("/api/devices") +def api_devices(): + if not _HAS_SD: + return jsonify({"error": "sounddevice not installed — pip install sounddevice"}), 500 + out = [] + for i, d in enumerate(sd.query_devices()): + if d["max_input_channels"] > 0: + out.append({ + "index": i, + "name": d["name"], + "channels": int(d["max_input_channels"]), + "rate": int(d["default_samplerate"]), + "default": (i == sd.default.device[0]), + }) + return jsonify(out) + + +@app.route("/api/wav", methods=["POST"]) +def api_wav(): + """Upload a WAV file for playback. Returns basic file info.""" + global _wav_tmp_path + if "wav" not in request.files: + return jsonify({"error": "No file provided"}), 400 + f = request.files["wav"] + try: + tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".wav") + f.save(tmp.name) + tmp.close() + if _wav_tmp_path and os.path.exists(_wav_tmp_path): + try: + os.unlink(_wav_tmp_path) + except OSError: + pass + _wav_tmp_path = tmp.name + wf = wave.open(tmp.name, "rb") + info = { + "ok": True, + "channels": wf.getnchannels(), + "rate": wf.getframerate(), + "bits": wf.getsampwidth() * 8, + "duration": round(wf.getnframes() / wf.getframerate(), 1), + } + wf.close() + return jsonify(info) + except Exception as exc: + return jsonify({"error": str(exc)}), 400 + + +@app.route("/api/start", methods=["POST"]) +def api_start(): + global _audio_stream, _bg_thread, _decoder, _osc_sender, _running + + if _running: + return jsonify({"error": "Already running"}), 400 + + data = request.get_json(force=True, silent=True) or {} + source = data.get("source", "live") # live | generate | wav + channel = int(data.get("channel", 0)) + target = str(data.get("target", "192.168.1.100")).strip() + port = int(data.get("port", 4210)) + address = str(data.get("address", "/dpx_tc001/custom/tc")).strip() + + # Build OSC sender + _osc_sender = None + if _HAS_OSC: + try: + _osc_sender = OSCSender(target, port, address) + except Exception as exc: + return jsonify({"error": f"OSC init failed: {exc}"}), 500 + + _stats.update(tc="--:--:--:--", fps=None, frames=0) + + # ── Live audio ──────────────────────────────────────────────────────────── + if source == "live": + if not _HAS_SD: + return jsonify({"error": "sounddevice not installed — pip install sounddevice"}), 500 + dev_idx = data.get("device") + try: + dev_info = ( + sd.query_devices(dev_idx, "input") if dev_idx is not None + else sd.query_devices(sd.default.device[0], "input") + ) + except Exception as exc: + return jsonify({"error": f"Cannot open device: {exc}"}), 400 + + n_ch = int(dev_info["max_input_channels"]) + if channel >= n_ch: + return jsonify({"error": f"Device has {n_ch}ch; channel {channel} out of range"}), 400 + rate = int(dev_info["default_samplerate"]) + + _decoder = LTCDecoder(sample_rate=rate, on_frame=_make_on_frame(_osc_sender)) + + def _audio_cb(indata, frames, time_info, status) -> None: + if _decoder is not None: + _decoder.feed(indata[:, channel].copy()) + + try: + _audio_stream = sd.InputStream( + device=dev_idx, channels=n_ch, samplerate=rate, + dtype="float32", blocksize=1024, callback=_audio_cb, + ) + _audio_stream.start() + _running = True + except Exception as exc: + return jsonify({"error": f"Cannot start audio: {exc}"}), 500 + + return jsonify({"ok": True, "source": "live", + "device": dev_info["name"], "rate": rate, "osc": _HAS_OSC}) + + # ── TC generator ────────────────────────────────────────────────────────── + if source == "generate": + fps_val = float(data.get("fps", 30.0)) + start_str = data.get("start_tc", "00:00:00:00") + try: + start_frame = _tc_to_frames(start_str, fps_val) + except ValueError as exc: + return jsonify({"error": str(exc)}), 400 + + _running = True + _bg_thread = threading.Thread( + target=_thread_generate, + args=(start_frame, fps_val, _osc_sender), + daemon=True, + ) + _bg_thread.start() + return jsonify({"ok": True, "source": "generate", + "start_tc": start_str, "fps": fps_val, "osc": _HAS_OSC}) + + # ── WAV playback ────────────────────────────────────────────────────────── + if source == "wav": + if not _wav_tmp_path or not os.path.exists(_wav_tmp_path): + return jsonify({"error": "No WAV file uploaded yet"}), 400 + + _running = True + _bg_thread = threading.Thread( + target=_thread_wav, + args=(_wav_tmp_path, channel, _osc_sender), + daemon=True, + ) + _bg_thread.start() + return jsonify({"ok": True, "source": "wav", "osc": _HAS_OSC}) + + return jsonify({"error": f"Unknown source: {source!r}"}), 400 + + +@app.route("/api/stop", methods=["POST"]) +def api_stop(): + global _audio_stream, _bg_thread, _decoder, _osc_sender, _running + _running = False + if _audio_stream is not None: + try: + _audio_stream.stop() + _audio_stream.close() + except Exception: + pass + _audio_stream = None + _decoder = None + _osc_sender = None + _broadcast({"tc": "--:--:--:--", "fps": None, "frames": 0, "stopped": True}) + return jsonify({"ok": True}) + + +@app.route("/api/d3", methods=["POST"]) +def api_d3(): + """Send a disguise d3 showcontrol OSC command.""" + if not _HAS_OSC: + return jsonify({"error": "python-osc not installed — pip install python-osc"}), 500 + data = request.get_json(force=True, silent=True) or {} + ip = str(data.get("ip", "192.168.1.100")).strip() + port = int(data.get("port", 7401)) + path = str(data.get("path", "")).strip() + args = data.get("args", None) # None | scalar | list + if not path.startswith("/"): + return jsonify({"error": "OSC path must start with /"}), 400 + try: + client = _UDPClient(ip, port) + client.send_message(path, args) + return jsonify({"ok": True, "path": path, "args": args}) + except Exception as exc: + return jsonify({"error": str(exc)}), 500 + + +@app.route("/api/stream") +def api_stream(): + q: queue.Queue = queue.Queue(maxsize=60) + with _lock: + _subscribers.append(q) + + def generate(): + yield f"data: {json.dumps(_stats)}\n\n" + try: + while True: + try: + msg = q.get(timeout=12) + yield f"data: {msg}\n\n" + except queue.Empty: + yield 'data: {"ping":true}\n\n' + finally: + with _lock: + if q in _subscribers: + _subscribers.remove(q) + + return Response( + stream_with_context(generate()), + mimetype="text/event-stream", + headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no", + "Connection": "keep-alive"}, + ) + + +# ── Embedded HTML/CSS/JS ──────────────────────────────────────────────────────── + +_HTML = r""" + + + + +LTC → OSC Bridge + + + +
+ + +
+ + +
+ + +
+
+ + + + LTC → OSC Bridge +
+
+ + +
+
--:--:--:--
+ +
+ + +
Source
+
+ + + + + + +
+ + +
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+ + +
+ +
No file selected
+
+
+ +
+ + +
+
OSC Target (dpx_tc001)
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ +
+ + + + + +
+
+ + + + + +
+ + + + +""" + +# ── Entry point ───────────────────────────────────────────────────────────────── + +DEFAULT_PORT = 8765 + + +def main() -> None: + import argparse + p = argparse.ArgumentParser( + description="LTC → OSC Bridge v2 — web UI with d3 control panel" + ) + p.add_argument("--port", type=int, default=DEFAULT_PORT, + help=f"Local web server port (default: {DEFAULT_PORT})") + p.add_argument("--no-browser", action="store_true", + help="Don't auto-open the browser") + args = p.parse_args() + + url = f"http://localhost:{args.port}" + print(f"\ndpx_tc001 LTC → OSC Bridge v2 (Web UI)") + print(f"{'─' * 42}") + print(f" Open : {url}") + print(f" Stop : Ctrl+C\n") + + if not args.no_browser: + def _open(): + time.sleep(0.9) + webbrowser.open(url) + threading.Thread(target=_open, daemon=True).start() + + app.run(host="127.0.0.1", port=args.port, + debug=False, threaded=True, use_reloader=False) + + +if __name__ == "__main__": + main() diff --git a/tools/ltc_osc_bridge/pyproject.toml b/tools/ltc_osc_bridge/pyproject.toml new file mode 100644 index 0000000000..f95c733e9d --- /dev/null +++ b/tools/ltc_osc_bridge/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["setuptools>=68.0"] +build-backend = "setuptools.backends.legacy:build" + +[project] +name = "ltc-osc-bridge" +version = "1.0.0" +description = "Decode SMPTE LTC from audio and send timecode via OSC UDP" +readme = "README.md" +license = { text = "MIT" } +requires-python = ">=3.9" +dependencies = [ + "sounddevice>=0.4.0", + "numpy>=1.21.0", + "python-osc>=1.8.0", + "flask>=2.0.0", +] + +[project.scripts] +ltc-osc-bridge = "ltc_osc_bridge:main" +ltc-osc-bridge-gui = "ltc_osc_bridge_gui:main" + +[tool.setuptools] +py-modules = ["ltc_osc_bridge"] diff --git a/tools/ltc_osc_bridge/requirements.txt b/tools/ltc_osc_bridge/requirements.txt new file mode 100644 index 0000000000..dce9fab442 --- /dev/null +++ b/tools/ltc_osc_bridge/requirements.txt @@ -0,0 +1,4 @@ +sounddevice>=0.4.0 +numpy>=1.21.0 +python-osc>=1.8.0 +flask>=2.0.0 diff --git a/usermods/dpx_matrix/dpx_api.h b/usermods/dpx_matrix/dpx_api.h new file mode 100644 index 0000000000..1ab3d2c575 --- /dev/null +++ b/usermods/dpx_matrix/dpx_api.h @@ -0,0 +1,386 @@ +// ================================================================================ +// dpx_api.h — HTTP Route Registration (AsyncWebServer) +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// Behavioral reference: SPEC.md §5 (HTTP API Reference) +// Implementation adapted from dpx_tc001 ServerManager.cpp (original work) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_api.h +// Purpose: Register all custom HTTP routes with WLED's AsyncWebServer instance. +// Call dpxRegisterRoutes() once from DpxMatrix::setup(). +// +// Routes registered: +// GET /ctrl, /browse, /api-ref, /screen, /fullscreen +// GET /api/loop, /api/apps, /api/custom, /api/settings, /api/time, +// /api/dev, /api/stats, /api/screen, /api/effects, /api/transitions, +// /api/osc/listeners, /api/reboot +// POST /api/notify, /api/notify/dismiss, /api/custom, /api/switch, +// /api/nextapp, /api/previousapp, /api/power, /api/settings, +// /api/moodlight, /api/indicator1/2/3, /api/rtttl, /api/sound, +// /api/apps, /api/reorder, /api/time, /api/syncntp, /api/rename, +// /api/tc, /api/dev, /api/osc/listeners +// DELETE /api/osc/listeners +// +// ================================================================================ + +#pragma once +#include +#include +#include "dpx_html.h" +#include "dpx_osc.h" +#include "dpx_tc.h" + +// Indicator pixel colors (rendered in handleOverlayDraw) +uint32_t dpxIndicator[3] = {0, 0, 0}; + +// Helper: get plain text body as String +static inline String dpxBody(AsyncWebServerRequest* req) { + if (req->hasParam("plain", true)) { + return req->getParam("plain", true)->value(); + } + return ""; +} + +// Helper: read and return /api/screen — 256 RGB values as JSON array +static String dpxScreenJson() { + DynamicJsonDocument doc(4096); + JsonArray arr = doc.to(); + for (int i = 0; i < 256; i++) { + uint32_t c = strip.getPixelColor(i); + // WLED returns WRGB — extract RGB + arr.add((uint32_t)(c & 0x00FFFFFF)); + } + String s; serializeJson(doc, s); return s; +} + +// Helper: basic stats JSON +static String dpxStatsJson() { + DynamicJsonDocument doc(512); + doc["version"] = "dpx_tc002"; + doc["uptime"] = millis() / 1000; + doc["ram"] = ESP.getFreeHeap(); + doc["ip"] = WiFi.localIP().toString(); + doc["rssi"] = WiFi.RSSI(); + doc["hostname"] = WiFi.getHostname(); + String s; serializeJson(doc, s); return s; +} + +static void dpxRegisterRoutes() { + // ── Web pages ────────────────────────────────────────────────────────── + server.on("/", HTTP_GET, [](AsyncWebServerRequest* r) { + r->redirect("/ctrl"); + }); + server.on("/ctrl", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send_P(200, "text/html", ctrl_html); + }); + server.on("/browse", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send_P(200, "text/html", browse_html); + }); + server.on("/api-ref", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send_P(200, "text/html", apiref_html); + }); + server.on("/screen", HTTP_GET, [](AsyncWebServerRequest* r) { + // /screen uses screenfull_html but since it has %%FPS%% placeholder, + // serve it statically; JS fetches /api/screen. + r->send_P(200, "text/html", screenfull_html); + }); + server.on("/fullscreen", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send_P(200, "text/html", screenfull_html); + }); + + // ── Read endpoints ──────────────────────────────────────────────────── + server.on("/api/loop", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, "application/json", dpxGetLoopJson()); + }); + server.on("/api/apps", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, "application/json", dpxGetAppsJson()); + }); + server.on("/api/custom", HTTP_GET, [](AsyncWebServerRequest* r) { + if (r->hasParam("name")) { + r->send(200, "application/json", + dpxGetCustomAppJson(r->getParam("name")->value())); + } else { + r->send(200, "application/json", dpxGetAppsJson()); + } + }); + server.on("/api/screen", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, "application/json", dpxScreenJson()); + }); + server.on("/api/stats", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, "application/json", dpxStatsJson()); + }); + server.on("/api/time", HTTP_GET, [](AsyncWebServerRequest* r) { + time_t now; struct tm ti; + time(&now); localtime_r(&now, &ti); + char buf[32]; strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &ti); + StaticJsonDocument<128> doc; + doc["local"] = buf; doc["utc"] = (long)now; + String j; serializeJson(doc, j); + r->send(200, "application/json", j); + }); + server.on("/api/dev", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, "application/json", dpxReadDevJson()); + }); + server.on("/api/osc/listeners", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, "application/json", dpxOscListenersJson()); + }); + server.on("/api/reboot", HTTP_ANY, [](AsyncWebServerRequest* r) { + r->send(200, "text/plain", "OK"); + delay(200); + ESP.restart(); + }); + // WLED's /api/effects and /api/transitions handled by WLED itself; add stubs + server.on("/api/effects", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, "application/json", F("[]")); + }); + server.on("/api/transitions", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, "application/json", F("[\"None\",\"Fade\",\"Slide\"]")); + }); + + // ── Control endpoints ───────────────────────────────────────────────── + server.on("/api/notify", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + String body((char*)data, len); + dpxPushNotification(body.c_str()) + ? r->send(200, "text/plain", "OK") + : r->send(500, "text/plain", "ParseError"); + }); + + server.on("/api/notify/dismiss", HTTP_ANY, [](AsyncWebServerRequest* r) { + dpxDismissNotification(); + r->send(200, "text/plain", "OK"); + }); + + server.on("/api/custom", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + String name = r->hasParam("name") ? r->getParam("name")->value() : ""; + String body((char*)data, len); + body.trim(); + if (name.length()) dpxSetCustomApp(name, body.c_str()); + r->send(200, "text/plain", "OK"); + }); + + server.on("/api/switch", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + String body((char*)data, len); + dpxSwitchToApp(body.c_str()) + ? r->send(200, "text/plain", "OK") + : r->send(500, "text/plain", "FAILED"); + }); + + server.on("/api/nextapp", HTTP_ANY, [](AsyncWebServerRequest* r) { + dpxNextApp(); r->send(200, "text/plain", "OK"); + }); + server.on("/api/previousapp", HTTP_ANY, [](AsyncWebServerRequest* r) { + dpxPrevApp(); r->send(200, "text/plain", "OK"); + }); + + server.on("/api/power", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + String body((char*)data, len); + StaticJsonDocument<64> doc; + if (!deserializeJson(doc, body) && doc.containsKey("power")) { + bool on = doc["power"].as(); + bri = on ? (briLast > 0 ? briLast : 128) : 0; + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + r->send(200, "text/plain", "OK"); + }); + + server.on("/api/tc", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + String body((char*)data, len); + body.trim(); body.replace("\"", ""); + if (body.length() >= 8) { + dpxPushTC(body); + r->send(200, "text/plain", "OK"); + } else { + r->send(400, "text/plain", "BadRequest"); + } + }); + + server.on("/api/dev", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + String body((char*)data, len); + dpxMergeDev(body.c_str()) + ? r->send(200, "text/plain", "OK") + : r->send(400, "text/plain", "BadRequest"); + }); + + server.on("/api/time", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + StaticJsonDocument<128> doc; + String body((char*)data, len); + if (!deserializeJson(doc, body) && doc.containsKey("utc")) { + time_t t = (time_t)doc["utc"].as(); + struct timeval tv = {t, 0}; + settimeofday(&tv, nullptr); + r->send(200, "text/plain", "OK"); + } else { + r->send(400, "text/plain", "BadRequest"); + } + }); + + server.on("/api/syncntp", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + String body((char*)data, len); + if (body.length() > 2) { + StaticJsonDocument<256> doc; + if (!deserializeJson(doc, body)) { + if (doc.containsKey("timezone")) { + configTzTime(doc["timezone"].as(), "pool.ntp.org"); + } + } + } + r->send(200, "text/plain", "OK"); + }); + + server.on("/api/rename", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + StaticJsonDocument<256> doc; + String body((char*)data, len); + if (deserializeJson(doc, body) || !doc.containsKey("from") || !doc.containsKey("to")) { + r->send(400, "text/plain", "BadRequest"); return; + } + String from = doc["from"].as(); + String to = doc["to"].as(); + if (!LittleFS.exists(from)) { r->send(404, "text/plain", "NotFound"); return; } + LittleFS.rename(from, to) + ? r->send(200, "text/plain", "OK") + : r->send(500, "text/plain", "Failed"); + }); + + server.on("/api/apps", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + // Reorder apps — array of name strings; rebuild loop in that order + DynamicJsonDocument doc(1024); + String body((char*)data, len); + if (deserializeJson(doc, body)) { r->send(400, "text/plain", "BadRequest"); return; } + // For now just acknowledge — reorder TODO + r->send(200, "text/plain", "OK"); + }); + + server.on("/api/reorder", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + r->send(200, "text/plain", "OK"); + }); + + // Indicator endpoints (1, 2, 3) + auto indicatorHandler = [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + // Extract indicator number from URL + String url = r->url(); + int num = url.charAt(url.length() - 1) - '0'; + if (num < 1 || num > 3) { r->send(400, "text/plain", "BadRequest"); return; } + StaticJsonDocument<256> doc; + String body((char*)data, len); + if (!deserializeJson(doc, body) && doc.containsKey("color")) { + JsonArray a = doc["color"].as(); + if (a.size() >= 3) { + uint32_t col = ((uint32_t)(uint8_t)a[0] << 16) + | ((uint32_t)(uint8_t)a[1] << 8) + | (uint32_t)(uint8_t)a[2]; + dpxIndicator[num - 1] = col; + } + } else { + dpxIndicator[num - 1] = 0; + } + r->send(200, "text/plain", "OK"); + }; + server.on("/api/indicator1", HTTP_POST, [](AsyncWebServerRequest* r){}, nullptr, indicatorHandler); + server.on("/api/indicator2", HTTP_POST, [](AsyncWebServerRequest* r){}, nullptr, indicatorHandler); + server.on("/api/indicator3", HTTP_POST, [](AsyncWebServerRequest* r){}, nullptr, indicatorHandler); + + // OSC listener add/delete + server.on("/api/osc/listeners", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + StaticJsonDocument<256> doc; + String body((char*)data, len); + if (deserializeJson(doc, body)) { r->send(400, "text/plain", "BadRequest"); return; } + String path = doc["path"].as(); + String channel = doc["channel"].as(); + String label = doc.containsKey("label") ? doc["label"].as() : channel; + if (!path.length() || !channel.length()) { r->send(400, "text/plain", "BadRequest"); return; } + // Update or add + bool found = false; + for (auto& lsr : dpxOscListeners) { + if (lsr.path == path) { lsr.channel = channel; lsr.label = label; found = true; break; } + } + if (!found) { DpxOscListener l; l.path=path; l.channel=channel; l.label=label; dpxOscListeners.push_back(l); } + dpxSaveOscListeners(); + r->send(200, "text/plain", "OK"); + }); + + server.on("/api/osc/listeners", HTTP_DELETE, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + StaticJsonDocument<128> doc; + String body((char*)data, len); + if (deserializeJson(doc, body)) { r->send(400, "text/plain", "BadRequest"); return; } + String path = doc["path"].as(); + dpxOscListeners.erase( + std::remove_if(dpxOscListeners.begin(), dpxOscListeners.end(), + [&](const DpxOscListener& l){ return l.path == path; }), + dpxOscListeners.end()); + dpxSaveOscListeners(); + r->send(200, "text/plain", "OK"); + }); + + // Settings passthrough — read/write WLED settings JSON (partial — BRI only for now) + server.on("/api/settings", HTTP_GET, [](AsyncWebServerRequest* r) { + StaticJsonDocument<256> doc; + doc["BRI"] = bri; + doc["ATIME"] = DPX_ATIME; + doc["ATRANS"] = DPX_ATRANS; + doc["SSPEED"] = DPX_SSPEED; + String s; serializeJson(doc, s); + r->send(200, "application/json", s); + }); + server.on("/api/settings", HTTP_POST, [](AsyncWebServerRequest* r) {}, + nullptr, + [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { + StaticJsonDocument<512> doc; + String body((char*)data, len); + if (!deserializeJson(doc, body)) { + if (doc.containsKey("BRI")) { bri = doc["BRI"].as(); stateUpdated(CALL_MODE_DIRECT_CHANGE); } + if (doc.containsKey("ATIME")) DPX_ATIME = doc["ATIME"].as(); + if (doc.containsKey("ATRANS")) DPX_ATRANS = doc["ATRANS"].as(); + if (doc.containsKey("SSPEED")) DPX_SSPEED = doc["SSPEED"].as(); + } + r->send(200, "text/plain", "OK"); + }); + + // Moodlight — placeholder (WLED handles this differently; delegate to WLED /json endpoint) + server.on("/api/moodlight", HTTP_ANY, [](AsyncWebServerRequest* r) { + r->send(200, "text/plain", "OK"); + }); + + // RTTTL — no buzzer in this build; accept and ignore for compatibility + server.on("/api/rtttl", HTTP_POST, [](AsyncWebServerRequest* r) { + r->send(200, "text/plain", "OK"); + }); + + // Sound — placeholder + server.on("/api/sound", HTTP_ANY, [](AsyncWebServerRequest* r) { + r->send(200, "text/plain", "OK"); + }); + + // Sleep — WLED handles deep sleep; placeholder + server.on("/api/sleep", HTTP_POST, [](AsyncWebServerRequest* r) { + r->send(200, "text/plain", "OK"); + }); +} diff --git a/usermods/dpx_matrix/dpx_apps.h b/usermods/dpx_matrix/dpx_apps.h new file mode 100644 index 0000000000..d309a6234d --- /dev/null +++ b/usermods/dpx_matrix/dpx_apps.h @@ -0,0 +1,372 @@ +// ================================================================================ +// dpx_apps.h — App Loop System +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// NOT derived from MatrixDisplayUi.cpp (AWTRIX CC BY-NC-SA 4.0). +// Written from scratch using SPEC.md §3-4 as behavioral reference. +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_apps.h +// Purpose: CustomApp struct, app loop vector, rotation timer, app management. +// Native apps (Time, Date, Temp) render their own content in render(). +// +// ================================================================================ + +#pragma once +#include +#include +#include +#include "dpx_text.h" +#include "dpx_persist.h" + +// ── Draw instruction (subset of SPEC.md §4.3) ──────────────────────────────── +struct DpxDrawCmd { + String cmd; // "dp","dl","dr","df","dc","dfc","dt","db" + // Numeric args (up to 5) + int n[5]; + String s; // string arg for "dt" command + uint32_t color; +}; + +// ── Custom App data (SPEC.md §4.1 key fields) ──────────────────────────────── +struct DpxCustomApp { + String text; + uint32_t color = 0xFFFFFF; + uint32_t background = 0x000000; + bool rainbow = false; + bool center = false; + bool noScroll = false; + int scrollSpeed = 100; // % of base speed + bool topText = false; + int duration = 0; // seconds; 0 = use DPX_ATIME + int16_t repeat = -1; + int progress = -1; // progress bar 0-100, -1=off + uint32_t pColor = 0x00FF00; + uint32_t pbColor = 0x1a1a1a; + uint64_t lifetime = 0; // auto-remove after N seconds (0=off) + unsigned long addedMs = 0; // millis() when app was added + bool save = false; + std::vector drawCmds; + + bool valid = false; // false = slot unused + + // Effective display duration in milliseconds + unsigned long durationMs() const { + int secs = (duration > 0) ? duration : DPX_ATIME; + return (unsigned long)secs * 1000UL; + } + + // True if this app has expired by lifetime + bool isExpired() const { + if (lifetime == 0 || addedMs == 0) return false; + return (millis() - addedMs) > (lifetime * 1000UL); + } +}; + +// ── App loop entry ──────────────────────────────────────────────────────────── +struct DpxApp { + String name; + DpxCustomApp data; + bool isNative = false; // Time, Date, Temp etc. +}; + +// ── OSC Listener Registry ───────────────────────────────────────────────────── +struct DpxOscListener { + String path; + String channel; + String label; +}; + +// ── Global app state ────────────────────────────────────────────────────────── +static std::vector dpxApps; // ordered app loop +static std::map dpxCustom; // named custom apps +static std::vector dpxOscListeners; + +static int dpxCurrentApp = 0; // index into dpxApps +static bool dpxAutoTrans = true; // auto-advance enabled +static unsigned long dpxAppStartMs = 0; // when current app was shown + +// Active scroll state — one per display +static DpxScrollState dpxScroll; + +// ── Parse a color from JSON value (string "#RRGGBB" or array [r,g,b]) ───────── +static uint32_t dpxParseColor(JsonVariant v, uint32_t def = 0xFFFFFF) { + if (v.is()) { + JsonArray a = v.as(); + if (a.size() >= 3) { + return ((uint32_t)(a[0].as()) << 16) + | ((uint32_t)(a[1].as()) << 8) + | (uint32_t)(a[2].as()); + } + } + if (v.is()) { + const char* s = v.as(); + if (s && s[0] == '#') { + return (uint32_t)strtol(s + 1, nullptr, 16); + } + } + return def; +} + +// ── Parse a CustomApp from JSON body ───────────────────────────────────────── +static DpxCustomApp dpxParseApp(const char* json) { + DpxCustomApp app; + DynamicJsonDocument doc(1024); + if (deserializeJson(doc, json)) return app; + + app.valid = true; + + if (doc.containsKey("text")) app.text = doc["text"].as(); + if (doc.containsKey("color")) app.color = dpxParseColor(doc["color"]); + if (doc.containsKey("background")) app.background = dpxParseColor(doc["background"], 0x000000); + if (doc.containsKey("rainbow")) app.rainbow = doc["rainbow"].as(); + if (doc.containsKey("center")) app.center = doc["center"].as(); + if (doc.containsKey("noScroll")) app.noScroll = doc["noScroll"].as(); + if (doc.containsKey("scrollSpeed")) app.scrollSpeed = doc["scrollSpeed"].as(); + if (doc.containsKey("topText")) app.topText = doc["topText"].as(); + if (doc.containsKey("duration")) app.duration = doc["duration"].as(); + if (doc.containsKey("repeat")) app.repeat = doc["repeat"].as(); + if (doc.containsKey("progress")) app.progress = doc["progress"].as(); + if (doc.containsKey("progressC")) app.pColor = dpxParseColor(doc["progressC"], 0x00FF00); + if (doc.containsKey("progressBC")) app.pbColor = dpxParseColor(doc["progressBC"], 0x1a1a1a); + if (doc.containsKey("lifetime")) app.lifetime = doc["lifetime"].as(); + if (doc.containsKey("save")) app.save = doc["save"].as(); + app.addedMs = millis(); + + // Draw commands + if (doc.containsKey("draw") && doc["draw"].is()) { + for (JsonObject o : doc["draw"].as()) { + DpxDrawCmd cmd; + if (o.containsKey("dp")) { cmd.cmd = "dp"; auto a = o["dp"].as(); cmd.n[0]=a[0];cmd.n[1]=a[1]; cmd.color=dpxParseColor(a[2]); app.drawCmds.push_back(cmd); } + else if (o.containsKey("df")) { cmd.cmd = "df"; auto a = o["df"].as(); cmd.n[0]=a[0];cmd.n[1]=a[1];cmd.n[2]=a[2];cmd.n[3]=a[3]; cmd.color=dpxParseColor(a[4]); app.drawCmds.push_back(cmd); } + else if (o.containsKey("dr")) { cmd.cmd = "dr"; auto a = o["dr"].as(); cmd.n[0]=a[0];cmd.n[1]=a[1];cmd.n[2]=a[2];cmd.n[3]=a[3]; cmd.color=dpxParseColor(a[4]); app.drawCmds.push_back(cmd); } + else if (o.containsKey("dl")) { cmd.cmd = "dl"; auto a = o["dl"].as(); cmd.n[0]=a[0];cmd.n[1]=a[1];cmd.n[2]=a[2];cmd.n[3]=a[3]; cmd.color=dpxParseColor(a[4]); app.drawCmds.push_back(cmd); } + else if (o.containsKey("dt")) { cmd.cmd = "dt"; auto a = o["dt"].as(); cmd.n[0]=a[0];cmd.n[1]=a[1]; cmd.s=a[2].as(); cmd.color=dpxParseColor(a[3]); app.drawCmds.push_back(cmd); } + } + } + + return app; +} + +// ── Render draw commands ────────────────────────────────────────────────────── +static void dpxExecDraw(const std::vector& cmds) { + for (const auto& c : cmds) { + if (c.cmd == "dp") { dpxSetPixel(c.n[0], c.n[1], c.color); } + else if (c.cmd == "df") { dpxFillRect(c.n[0], c.n[1], c.n[2], c.n[3], c.color); } + else if (c.cmd == "dr") { dpxDrawRect(c.n[0], c.n[1], c.n[2], c.n[3], c.color); } + else if (c.cmd == "dl") { + // Simple line using Bresenham + int x0=c.n[0],y0=c.n[1],x1=c.n[2],y1=c.n[3]; + int dx=abs(x1-x0), dy=abs(y1-y0), sx=x0-dy){err-=dy;x0+=sx;} if(e2= 0) { + dpxDrawProgressBar(app.progress, app.pColor, app.pbColor); + } + + int textY = app.topText ? 0 : 1; // text row + int textW = dpxTextPixelWidth(app.text.c_str()); + + if (app.noScroll || textW <= DPX_MATRIX_W) { + // Static: center or left-align + int x = 0; + if (app.center && textW < DPX_MATRIX_W) x = (DPX_MATRIX_W - textW) / 2; + dpxRenderText(x, textY, app.text.c_str(), app.color, app.rainbow); + return true; // static apps never "complete" + } + + // Scrolling + if (!dpxScroll.active || dpxScroll.text != app.text) { + dpxScroll.start(app.text, app.color, app.rainbow, textY, app.scrollSpeed, app.repeat); + } + bool done = dpxScroll.tick(); + dpxScroll.render(); + return !done; +} + +// ── App loop management ─────────────────────────────────────────────────────── + +// Rebuild dpxApps from dpxCustom (preserves native apps, appends custom ones). +static void dpxRebuildLoop() { + std::vector newList; + // Always-first native apps + { DpxApp a; a.name="Time"; a.isNative=true; newList.push_back(a); } + { DpxApp a; a.name="Date"; a.isNative=true; newList.push_back(a); } + // Custom apps in insertion order + for (auto& kv : dpxCustom) { + if (kv.second.valid) { + DpxApp a; + a.name = kv.first; + a.data = kv.second; + a.isNative = false; + newList.push_back(a); + } + } + dpxApps = newList; + if (dpxCurrentApp >= (int)dpxApps.size()) dpxCurrentApp = 0; +} + +// Add or update a custom app by name. Empty body = delete. +static void dpxSetCustomApp(const String& name, const char* json) { + if (!json || strlen(json) <= 2) { + // Empty JSON or null → delete + dpxCustom.erase(name); + } else { + DpxCustomApp app = dpxParseApp(json); + if (app.valid) dpxCustom[name] = app; + } + dpxRebuildLoop(); +} + +// Advance to next app +static void dpxNextApp() { + if (dpxApps.empty()) return; + dpxCurrentApp = (dpxCurrentApp + 1) % dpxApps.size(); + dpxAppStartMs = millis(); + dpxScroll.stop(); +} + +// Go to previous app +static void dpxPrevApp() { + if (dpxApps.empty()) return; + dpxCurrentApp = (dpxCurrentApp + (int)dpxApps.size() - 1) % dpxApps.size(); + dpxAppStartMs = millis(); + dpxScroll.stop(); +} + +// Switch to a named app; JSON body: {"name":"AppName"} +static bool dpxSwitchToApp(const char* json) { + DynamicJsonDocument doc(128); + if (deserializeJson(doc, json)) return false; + String name = doc["name"].as(); + for (int i = 0; i < (int)dpxApps.size(); i++) { + if (dpxApps[i].name == name) { + dpxCurrentApp = i; + dpxAppStartMs = millis(); + dpxScroll.stop(); + return true; + } + } + return false; +} + +// App loop JSON: {"AppName": index, ...} +static String dpxGetLoopJson() { + DynamicJsonDocument doc(1024); + for (int i = 0; i < (int)dpxApps.size(); i++) { + doc[dpxApps[i].name] = i; + } + String s; serializeJson(doc, s); return s; +} + +// Apps-with-icon JSON array (SPEC.md §5 /api/apps) +static String dpxGetAppsJson() { + DynamicJsonDocument doc(2048); + JsonArray arr = doc.to(); + for (auto& a : dpxApps) { + JsonObject o = arr.createNestedObject(); + o["name"] = a.name; + o["native"] = a.isNative; + } + String s; serializeJson(doc, s); return s; +} + +// Return JSON of a specific custom app's current state +static String dpxGetCustomAppJson(const String& name) { + if (dpxCustom.find(name) == dpxCustom.end()) return F("{}"); + const DpxCustomApp& a = dpxCustom[name]; + DynamicJsonDocument doc(512); + doc["text"] = a.text; + doc["color"] = a.color; + doc["background"] = a.background; + doc["rainbow"] = a.rainbow; + doc["center"] = a.center; + doc["noScroll"] = a.noScroll; + doc["scrollSpeed"] = a.scrollSpeed; + doc["duration"] = a.duration; + doc["progress"] = a.progress; + String s; serializeJson(doc, s); return s; +} + +// ── App loop tick (call from loop()) ───────────────────────────────────────── +// Advances app pointer when current app's duration expires. +static void dpxAppLoopTick() { + if (dpxApps.empty()) return; + + // Prune expired lifetime apps + for (auto it = dpxCustom.begin(); it != dpxCustom.end(); ) { + if (it->second.isExpired()) { it = dpxCustom.erase(it); dpxRebuildLoop(); } + else ++it; + } + + if (!dpxAutoTrans) return; + if (dpxApps.empty()) return; + + unsigned long now = millis(); + unsigned long dur = dpxApps[dpxCurrentApp].isNative + ? (unsigned long)DPX_ATIME * 1000UL + : dpxApps[dpxCurrentApp].data.durationMs(); + + if (now - dpxAppStartMs >= dur) { + dpxNextApp(); + } +} + +// ── Render the current app frame ───────────────────────────────────────────── +// Called from handleOverlayDraw(). +static void dpxRenderCurrentApp() { + if (dpxApps.empty()) { + dpxClear(); + dpxRenderText(0, 0, "NO APP", 0x444444); + return; + } + + DpxApp& app = dpxApps[dpxCurrentApp]; + if (app.isNative) { + dpxClear(); + if (app.name == "Time") dpxRenderNativeTime(); + else if (app.name == "Date") dpxRenderNativeDate(); + } else { + dpxRenderApp(app.data); + } +} diff --git a/usermods/dpx_matrix/dpx_buzzer.h b/usermods/dpx_matrix/dpx_buzzer.h new file mode 100644 index 0000000000..04643705c8 --- /dev/null +++ b/usermods/dpx_matrix/dpx_buzzer.h @@ -0,0 +1,201 @@ +// ================================================================================ +// dpx_buzzer.h — Non-blocking RTTTL tone player for TC001 (GPIO 15) +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_buzzer.h +// Purpose: Parses an RTTTL string into a flat note/duration sequence and steps +// through it from loop() without any blocking delays. +// +// Uses Arduino tone()/noTone() which on ESP32 drives a single LEDC +// channel. This is safe alongside WS2812B LEDs because WLED drives +// those via the RMT peripheral, not LEDC. +// +// Public API: +// dpxBuzzerInit() — call once from setup(); drives pin LOW +// dpxBuzzerPlay(const char*) — start playing an RTTTL string +// dpxBuzzerStop() — immediately silence and reset +// dpxBuzzerTick() — call every loop(); advances the sequence +// +// RTTTL format: "Title:d=4,o=5,b=120:e,e,e,c,e,g,G" +// d = default note duration (1/2/4/8/16/32) +// o = default octave (4–7) +// b = BPM +// Notes: [dur][pitch][#][oct][.] — # = sharp, . = dotted (×1.5) +// +// ================================================================================ + +#pragma once +#include "Arduino.h" + +// AI: below section was generated by an AI + +#define DPX_BUZZER_PIN 15 +#define DPX_BUZZER_MAX_NOTES 96 // max notes parsed from one RTTTL string + +// ── Chromatic frequency table — octave 4 base (C4..B4, Hz) ────────────────── +// Index: 0=C 1=C# 2=D 3=D# 4=E 5=F 6=F# 7=G 8=G# 9=A 10=A# 11=B +static const uint16_t DPX_NOTE_HZ[12] PROGMEM = { + 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494 +}; + +// Map RTTTL pitch letter → chromatic index (0-11). Returns -1 for 'p' (pause). +static int _dpxPitchIdx(char c) { + switch (c) { + case 'c': return 0; + case 'd': return 2; + case 'e': return 4; + case 'f': return 5; + case 'g': return 7; + case 'a': return 9; + case 'b': return 11; + default: return -1; // 'p' = pause, unknown = silence + } +} + +struct DpxBuzzerNote { + uint16_t freq; // Hz — 0 means silence/pause + uint16_t ms; // duration in milliseconds (capped at 4000) +}; + +static DpxBuzzerNote _bzNotes[DPX_BUZZER_MAX_NOTES]; +static uint8_t _bzCount = 0; +static uint8_t _bzIdx = 0; +static bool _bzPlaying = false; +static unsigned long _bzNoteMs = 0; // millis() when current note started + +// ── Parse RTTTL string into _bzNotes[] ─────────────────────────────────────── +static void _dpxRtttlParse(const char* rtttl) { + _bzCount = 0; + + // Skip title (up to first ':') + const char* p = rtttl; + while (*p && *p != ':') p++; + if (!*p) return; + p++; // skip ':' + + // Parse header defaults: d=4,o=5,b=120 + int defDur = 4, defOct = 5, bpm = 120; + while (*p && *p != ':') { + while (*p == ' ' || *p == ',') p++; + if (!*p || *p == ':') break; + char key = *p++; + if (*p != '=') continue; + p++; + int val = 0; + while (*p >= '0' && *p <= '9') val = val * 10 + (*p++ - '0'); + if (key == 'd') defDur = max(1, val); + else if (key == 'o') defOct = constrain(val, 4, 7); + else if (key == 'b') bpm = max(1, val); + } + if (!*p) return; + p++; // skip second ':' + + // Whole-note duration in ms = 60000ms/beat × 4 beats/whole = 240000/BPM + uint32_t wholeMs = 240000UL / (uint32_t)bpm; + + while (*p && _bzCount < DPX_BUZZER_MAX_NOTES) { + // Skip whitespace and commas between notes + while (*p == ' ' || *p == ',') p++; + if (!*p) break; + + // Optional explicit duration digits + int dur = 0; + while (*p >= '0' && *p <= '9') dur = dur * 10 + (*p++ - '0'); + if (dur == 0) dur = defDur; + + // Pitch letter (c d e f g a b p) + if (!*p) break; + char pitch = tolower((unsigned char)*p++); + int idx = _dpxPitchIdx(pitch); + + // Optional sharp + bool sharp = false; + if (*p == '#') { sharp = true; p++; } + + // Optional octave digit + int oct = defOct; + if (*p >= '4' && *p <= '7') oct = (int)(*p++ - '0'); + + // Optional dot (duration × 1.5) + bool dotted = false; + if (*p == '.') { dotted = true; p++; } + + // Compute duration + uint32_t durMs = wholeMs / (uint32_t)dur; + if (dotted) durMs = durMs * 3 / 2; + durMs = constrain(durMs, (uint32_t)10, (uint32_t)4000); + + // Compute frequency (0 = pause) + uint16_t freq = 0; + if (idx >= 0) { + int chromIdx = idx + (sharp ? 1 : 0); + // Base frequency from table (octave 4) + uint32_t f = pgm_read_word(&DPX_NOTE_HZ[chromIdx % 12]); + // Octave shift relative to 4 + int shift = oct - 4 + (chromIdx / 12); + if (shift > 0) f <<= shift; + else if (shift < 0) f >>= (-shift); + freq = (uint16_t)constrain((int32_t)f, 20, 20000); + } + + _bzNotes[_bzCount++] = { freq, (uint16_t)durMs }; + } +} + +// ── Public API ──────────────────────────────────────────────────────────────── +static void dpxBuzzerStop(); // forward declaration + +// Call once from setup() — ensures pin is OUTPUT and driven LOW. +static void dpxBuzzerInit() { + pinMode(DPX_BUZZER_PIN, OUTPUT); + digitalWrite(DPX_BUZZER_PIN, LOW); +} + +// Start playing an RTTTL string. Call dpxBuzzerTick() from loop() to advance. +static void dpxBuzzerPlay(const char* rtttl) { + dpxBuzzerStop(); // stop any current melody first + if (!rtttl || !*rtttl) return; + _dpxRtttlParse(rtttl); + if (_bzCount == 0) return; + + _bzIdx = 0; + _bzPlaying = true; + _bzNoteMs = millis(); + + // Start the first note immediately + if (_bzNotes[0].freq > 0) tone(DPX_BUZZER_PIN, _bzNotes[0].freq); + else noTone(DPX_BUZZER_PIN); +} + +// Immediately stop playback and silence the buzzer. +static void dpxBuzzerStop() { + noTone(DPX_BUZZER_PIN); + digitalWrite(DPX_BUZZER_PIN, LOW); + _bzPlaying = false; + _bzIdx = 0; + _bzCount = 0; +} + +// Advance the note sequencer — call from loop() every iteration. +static void dpxBuzzerTick() { + if (!_bzPlaying) return; + + unsigned long now = millis(); + if (now - _bzNoteMs < _bzNotes[_bzIdx].ms) return; // still in this note + + // Move to next note + _bzIdx++; + if (_bzIdx >= _bzCount) { + dpxBuzzerStop(); + return; + } + _bzNoteMs = now; + if (_bzNotes[_bzIdx].freq > 0) tone(DPX_BUZZER_PIN, _bzNotes[_bzIdx].freq); + else noTone(DPX_BUZZER_PIN); +} + +// AI: end diff --git a/usermods/dpx_matrix/dpx_firstboot.h b/usermods/dpx_matrix/dpx_firstboot.h new file mode 100644 index 0000000000..a2f800befd --- /dev/null +++ b/usermods/dpx_matrix/dpx_firstboot.h @@ -0,0 +1,104 @@ +// ================================================================================ +// dpx_firstboot.h — First-Boot Config Injection +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_firstboot.h +// Purpose: On first boot (no /cfg.json on LittleFS), write a complete default +// configuration for the Ulanzi TC001 hardware so the device is usable +// out of the box without needing the WLED setup wizard. +// +// Pre-configured defaults: +// - LED: GPIO 32, 256 WS2812B, GRB, no 2D yet (set via WLED UI) +// - AP: behav=1 (always open when disconnected, no timeout) +// - AP SSID: dpx-tc002 password: dubpixel1 +// - mDNS: dpx-tc002 +// - Name: dpx_tc002 +// ================================================================================ + +#pragma once + +static void dpxFirstBoot() { + // Only run if /cfg.json does not exist (genuine first boot or wiped flash) + if (LittleFS.exists(F("/cfg.json"))) return; + + DEBUG_PRINTLN(F("DpxMatrix: first boot — writing default cfg.json")); + + // Write a minimal but complete cfg.json that WLED will load at next boot. + // We use a raw string to keep it readable and avoid ArduinoJson overhead. + // Field reference: wled00/cfg.cpp deserializeConfig() + // + // Key fields set here: + // id.mdns / id.name — hostname and device name + // ap.ssid / ap.psk — AP credentials (behav 1 = always open when disco) + // hw.led.ins — GPIO 32, 256 WS2812B GRB + // hw.btn.ins — left=GPIO26 short-press (type 2 = push button) + // light.tr.dur — transition duration 0 (instant, better for matrix) + + File f = LittleFS.open(F("/cfg.json"), "w"); + if (!f) { + DEBUG_PRINTLN(F("DpxMatrix: failed to open /cfg.json for writing")); + return; + } + + f.print(F( + "{" + "\"rev\":[1,0]," + "\"id\":{" + "\"mdns\":\"dpx-tc002\"," + "\"name\":\"dpx_tc002\"," + "\"inv\":\"TC001\"," + "\"sui\":false" + "}," + "\"ap\":{" + "\"ssid\":\"dpx-tc002\"," + "\"psk\":\"dubpixel1\"," + "\"chan\":6," + "\"hide\":0," + "\"behav\":1" + "}," + "\"wifi\":{\"sleep\":false}," + "\"hw\":{" + "\"led\":{" + "\"total\":256," + "\"maxpwr\":8500," + "\"fps\":42," + "\"ins\":[{" + "\"start\":0," + "\"len\":256," + "\"pin\":[32]," + "\"order\":0," + "\"rev\":false," + "\"skip\":0," + "\"type\":22," + "\"ref\":false," + "\"rgbwm\":255," + "\"freq\":0," + "\"ledma\":55," + "\"drv\":0" + "}]" + "}," + "\"btn\":{" + "\"max\":3," + "\"pull\":true," + "\"ins\":[" + "{\"type\":2,\"pin\":[26],\"macros\":[0,0,0]}," + "{\"type\":2,\"pin\":[14],\"macros\":[0,0,0]}," + "{\"type\":2,\"pin\":[27],\"macros\":[0,0,0]}" + "]" + "}" + "}," + "\"light\":{" + "\"tr\":{\"dur\":0,\"rpc\":5,\"hrp\":false}" + "}," + "\"def\":{\"ps\":0,\"on\":true,\"bri\":128}," + "\"ota\":{\"lock\":false}" + "}" + )); + + f.close(); + DEBUG_PRINTLN(F("DpxMatrix: default cfg.json written — reboot to apply")); +} diff --git a/usermods/dpx_matrix/dpx_font.h b/usermods/dpx_matrix/dpx_font.h new file mode 100644 index 0000000000..77efcd025e --- /dev/null +++ b/usermods/dpx_matrix/dpx_font.h @@ -0,0 +1,146 @@ +// ================================================================================ +// dpx_font.h — 5×7 Pixel Bitmap Font +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// NOT derived from AwtrixFont.h (CC BY-NC-SA 4.0). Written from scratch. +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_font.h +// Purpose: 5-wide × 7-tall pixel font for 32×8 LED matrix display. +// Column-major storage: 5 bytes per glyph, each byte = 1 column. +// Bit 0 = top row, Bit 6 = bottom row. Bit 7 unused. +// Covers printable ASCII 0x20 (space) through 0x7E (~). +// +// Usage: +// const uint8_t *glyph = dpxFontGlyph('A'); // returns 5-byte pointer +// uint8_t col0 = glyph[0]; // leftmost column bitmap +// +// ================================================================================ + +#pragma once +#include + +// Glyph width in pixels (columns) +static const uint8_t DPX_FONT_W = 5; +// Glyph height in pixels (rows) +static const uint8_t DPX_FONT_H = 7; +// Gap between characters in pixels +static const uint8_t DPX_FONT_GAP = 1; + +// 5×7 bitmap font — column-major, LSB = top row. +// 95 characters, ASCII 0x20 (space) to 0x7E (~). +// Each row: 5 column bytes for one character. +static const uint8_t DPX_FONT[95][5] PROGMEM = { + {0x00,0x00,0x00,0x00,0x00}, // 0x20 space + {0x00,0x00,0x5F,0x00,0x00}, // 0x21 ! + {0x00,0x07,0x00,0x07,0x00}, // 0x22 " + {0x14,0x7F,0x14,0x7F,0x14}, // 0x23 # + {0x24,0x2A,0x7F,0x2A,0x12}, // 0x24 $ + {0x23,0x13,0x08,0x64,0x62}, // 0x25 % + {0x36,0x49,0x55,0x22,0x50}, // 0x26 & + {0x00,0x05,0x03,0x00,0x00}, // 0x27 ' + {0x00,0x1C,0x22,0x41,0x00}, // 0x28 ( + {0x00,0x41,0x22,0x1C,0x00}, // 0x29 ) + {0x08,0x2A,0x1C,0x2A,0x08}, // 0x2A * + {0x08,0x08,0x3E,0x08,0x08}, // 0x2B + + {0x00,0x50,0x30,0x00,0x00}, // 0x2C , + {0x08,0x08,0x08,0x08,0x08}, // 0x2D - + {0x00,0x60,0x60,0x00,0x00}, // 0x2E . + {0x20,0x10,0x08,0x04,0x02}, // 0x2F / + {0x3E,0x51,0x49,0x45,0x3E}, // 0x30 0 + {0x00,0x42,0x7F,0x40,0x00}, // 0x31 1 + {0x42,0x61,0x51,0x49,0x46}, // 0x32 2 + {0x21,0x41,0x45,0x4B,0x31}, // 0x33 3 + {0x18,0x14,0x12,0x7F,0x10}, // 0x34 4 + {0x27,0x45,0x45,0x45,0x39}, // 0x35 5 + {0x3C,0x4A,0x49,0x49,0x30}, // 0x36 6 + {0x01,0x71,0x09,0x05,0x03}, // 0x37 7 + {0x36,0x49,0x49,0x49,0x36}, // 0x38 8 + {0x06,0x49,0x49,0x29,0x1E}, // 0x39 9 + {0x00,0x36,0x36,0x00,0x00}, // 0x3A : + {0x00,0x56,0x36,0x00,0x00}, // 0x3B ; + {0x08,0x14,0x22,0x41,0x00}, // 0x3C < + {0x14,0x14,0x14,0x14,0x14}, // 0x3D = + {0x00,0x41,0x22,0x14,0x08}, // 0x3E > + {0x02,0x01,0x51,0x09,0x06}, // 0x3F ? + {0x32,0x49,0x79,0x41,0x3E}, // 0x40 @ + {0x7E,0x11,0x11,0x11,0x7E}, // 0x41 A + {0x7F,0x49,0x49,0x49,0x36}, // 0x42 B + {0x3E,0x41,0x41,0x41,0x22}, // 0x43 C + {0x7F,0x41,0x41,0x22,0x1C}, // 0x44 D + {0x7F,0x49,0x49,0x49,0x41}, // 0x45 E + {0x7F,0x09,0x09,0x09,0x01}, // 0x46 F + {0x3E,0x41,0x49,0x49,0x7A}, // 0x47 G + {0x7F,0x08,0x08,0x08,0x7F}, // 0x48 H + {0x00,0x41,0x7F,0x41,0x00}, // 0x49 I + {0x20,0x40,0x41,0x3F,0x01}, // 0x4A J + {0x7F,0x08,0x14,0x22,0x41}, // 0x4B K + {0x7F,0x40,0x40,0x40,0x40}, // 0x4C L + {0x7F,0x02,0x0C,0x02,0x7F}, // 0x4D M + {0x7F,0x04,0x08,0x10,0x7F}, // 0x4E N + {0x3E,0x41,0x41,0x41,0x3E}, // 0x4F O + {0x7F,0x09,0x09,0x09,0x06}, // 0x50 P + {0x3E,0x41,0x51,0x21,0x5E}, // 0x51 Q + {0x7F,0x09,0x19,0x29,0x46}, // 0x52 R + {0x46,0x49,0x49,0x49,0x31}, // 0x53 S + {0x01,0x01,0x7F,0x01,0x01}, // 0x54 T + {0x3F,0x40,0x40,0x40,0x3F}, // 0x55 U + {0x1F,0x20,0x40,0x20,0x1F}, // 0x56 V + {0x3F,0x40,0x38,0x40,0x3F}, // 0x57 W + {0x63,0x14,0x08,0x14,0x63}, // 0x58 X + {0x07,0x08,0x70,0x08,0x07}, // 0x59 Y + {0x61,0x51,0x49,0x45,0x43}, // 0x5A Z + {0x00,0x7F,0x41,0x41,0x00}, // 0x5B [ + {0x02,0x04,0x08,0x10,0x20}, // 0x5C backslash + {0x00,0x41,0x41,0x7F,0x00}, // 0x5D ] + {0x04,0x02,0x01,0x02,0x04}, // 0x5E ^ + {0x40,0x40,0x40,0x40,0x40}, // 0x5F _ + {0x00,0x01,0x02,0x04,0x00}, // 0x60 ` + {0x20,0x54,0x54,0x54,0x78}, // 0x61 a + {0x7F,0x48,0x44,0x44,0x38}, // 0x62 b + {0x38,0x44,0x44,0x44,0x20}, // 0x63 c + {0x38,0x44,0x44,0x48,0x7F}, // 0x64 d + {0x38,0x54,0x54,0x54,0x18}, // 0x65 e + {0x08,0x7E,0x09,0x01,0x02}, // 0x66 f + {0x0C,0x52,0x52,0x52,0x3E}, // 0x67 g + {0x7F,0x08,0x04,0x04,0x78}, // 0x68 h + {0x00,0x44,0x7D,0x40,0x00}, // 0x69 i + {0x20,0x40,0x44,0x3D,0x00}, // 0x6A j + {0x7F,0x10,0x28,0x44,0x00}, // 0x6B k + {0x00,0x41,0x7F,0x40,0x00}, // 0x6C l + {0x7C,0x04,0x18,0x04,0x78}, // 0x6D m + {0x7C,0x08,0x04,0x04,0x78}, // 0x6E n + {0x38,0x44,0x44,0x44,0x38}, // 0x6F o + {0x7C,0x14,0x14,0x14,0x08}, // 0x70 p + {0x08,0x14,0x14,0x18,0x7C}, // 0x71 q + {0x7C,0x08,0x04,0x04,0x00}, // 0x72 r + {0x48,0x54,0x54,0x54,0x20}, // 0x73 s + {0x04,0x3F,0x44,0x40,0x20}, // 0x74 t + {0x3C,0x40,0x40,0x20,0x7C}, // 0x75 u + {0x1C,0x20,0x40,0x20,0x1C}, // 0x76 v + {0x3C,0x40,0x30,0x40,0x3C}, // 0x77 w + {0x44,0x28,0x10,0x28,0x44}, // 0x78 x + {0x0C,0x50,0x50,0x50,0x3C}, // 0x79 y + {0x44,0x64,0x54,0x4C,0x44}, // 0x7A z + {0x00,0x08,0x36,0x41,0x00}, // 0x7B { + {0x00,0x00,0x7F,0x00,0x00}, // 0x7C | + {0x00,0x41,0x36,0x08,0x00}, // 0x7D } + {0x10,0x08,0x08,0x10,0x08}, // 0x7E ~ +}; + +// Return pointer to the 5 column bytes for a character. +// Falls back to '?' for characters outside the printable ASCII range. +inline const uint8_t* dpxFontGlyph(char c) { + uint8_t idx = (uint8_t)c; + if (idx < 0x20 || idx > 0x7E) idx = 0x3F; // '?' + return DPX_FONT[idx - 0x20]; +} + +// Pixel width of a string (includes inter-character gap, no trailing gap). +inline int dpxTextPixelWidth(const char* str) { + if (!str || *str == '\0') return 0; + int len = strlen(str); + return len * (DPX_FONT_W + DPX_FONT_GAP) - DPX_FONT_GAP; +} diff --git a/usermods/dpx_matrix/dpx_html.h b/usermods/dpx_matrix/dpx_html.h new file mode 100644 index 0000000000..95d775890d --- /dev/null +++ b/usermods/dpx_matrix/dpx_html.h @@ -0,0 +1,1366 @@ +// ================================================================================ +// dpx_html.h — PROGMEM Web UI Pages +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// Pages: /api-ref, /browse, /ctrl, /screen, /fullscreen +// Ported from dpx_tc001/src/htmls.h (original work, not AWTRIX-derived). +// EXCLUDED: custom_html, screen_html, backup_html (contain AWTRIX references). +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ + +#pragma once + +static const char apiref_html[] PROGMEM = R"APIREF( +API Reference + +

📄 API Reference

+
+ + + + +

HTTP Endpoints

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodURLBody / Notes
GET/api/statsDevice stats (RAM, uptime, battery…)
GET/api/screenCurrent matrix as 256× 24-bit int array
GET/api/effectsArray of effect name strings
GET/api/transitionsArray of transition name strings
GET/api/loopOrdered app list
GET/api/appsApp list with icons
GET/api/settingsCurrent settings JSON
POST/api/notifyOne-shot notification — see JSON keys below
POST/api/notify/dismissDismiss held notification (empty body)
POST/api/custom?name=appnameCreate/update persistent custom app
POST/api/switch{"name":"Time"} — jump to app
POST/api/nextappempty body
POST/api/previousappempty body
POST/api/power{"power":true}
POST/api/sleep{"sleep":60} — seconds
POST/api/settingsSettings JSON — see keys below
POST/api/moodlight{"color":[255,80,0],"brightness":170}
POST/api/indicator1 /2 /3{"color":[255,0,0],"blink":500}
POST/api/rtttlRaw RTTTL string as plain body
POST/api/sound{"sound":"alarm"}
POST/api/reorderArray of app name strings — set loop order
POST/api/doupdateTrigger OTA firmware update (empty body)
GET/api/timeCurrent device time: {"local":"2026-07-14T15:30:00","utc":1752506200}
POST/api/time{"utc":1752506200} — set clock via settimeofday()
POST/api/syncntpRe-trigger NTP sync with current server + timezone settings
POST/api/rename{"from":"/ICONS/old.jpg","to":"/ICONS/new.jpg"}
GET/api/rebootReboot device
GET/screenLive view page
GET/ctrlControl panel
GET/browseCommunity browser
+ +

Quick curl examples

+
curl -X POST http://[IP]/api/notify \ + -H "Content-Type: application/json" \ + -d '{"text":"Hello!","color":[255,200,0],"icon":"87","duration":8}'
+
curl -X POST http://[IP]/api/custom?name=myapp \ + -H "Content-Type: application/json" \ + -d '{"text":"Always on","rainbow":true,"scrollSpeed":80}'
+ + +

Notify & Custom App — JSON Keys

+

All keys optional. N=notify only   C=custom app only   B=both

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescriptionDefault
textstring/arrayText to display. Array = colored fragments: [{"t":"Hi","c":"FF0000"}]B
textCaseint0=global, 1=UPPER, 2=as-sent0B
topTextboolDraw text on top rowfalseB
textOffsetintX-offset for text start0B
centerboolCenter short non-scrolling texttrueB
colorstr/[r,g,b]Text/bar/line colorB
gradient[c1,c2]Two-color text gradientB
backgroundstr/[r,g,b]Background fill colorB
rainbowboolRGB rainbow per letterfalseB
blinkTextintBlink text every N msB
fadeTextintFade text in/out every N msB
iconstringIcon filename (no ext) or LaMetric ID, or 8×8 JPG as base64B
pushIconint0=fixed, 1=scroll+gone, 2=scroll+loop0B
noScrollboolDisable text scrollingfalseB
scrollSpeedintScroll speed % of default100B
durationintDisplay time in seconds5B
repeatintTimes to scroll before ending (-1=forever)-1B
holdboolHold notification until dismissedfalseN
stackboolStack notification; false=replace currenttrueN
wakeupboolWake matrix from sleep for notificationfalseN
soundstringRTTTL filename (no ext) or DFPlayer 4-digit numberN
rtttlstringInline RTTTL stringN
loopSoundboolLoop sound for notification durationfalseN
effectstringBackground effect name (see Effects)B
effectSettingsobject{"speed":3,"palette":"Rainbow","blend":true}B
overlaystringPer-app overlay: snow/rain/drizzle/storm/thunder/frost/clearB
barint[]Bar chart data (max 16 values, 11 with icon)B
lineint[]Line chart data (same limits)B
autoscaleboolAutoscale bar/line charttrueB
barBCstr/[r,g,b]Bar background color0B
progressintProgress bar 0–100 (-1=off)-1B
progressCstr/[r,g,b]Progress bar fill colorB
progressBCstr/[r,g,b]Progress bar background colorB
drawobject[]Drawing instructions array — see Draw CommandsB
lifetimeintRemove custom app if no update after N seconds0C
posintLoop position (0-based, set on first push)C
saveboolPersist custom app across reboots (avoid for high-freq updates)falseC
clientsstring[]Forward notification to other devices (IP or MQTT prefix)N
+ + +

Settings Keys — POST /api/settings or GET to read

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescriptionRange
BRIintBrightness0–255
ABRIboolAuto brightnesstrue/false
ATIMEintApp display duration (s)>0
TEFFintTransition effect index0–10
TSPEEDintTransition duration (ms)>0
ATRANSboolAuto advance appstrue/false
TCOLstr/[r,g,b]Global text color
TMODEintTime app layout (0–6)0–6
TFORMATstringTime format e.g. %H:%M
DFORMATstringDate format e.g. %d.%m.%y
UPPERCASEboolForce uppercase text globallytrue/false
SSPEEDintGlobal scroll speed %1–200
OVERLAYstringGlobal overlay effectsee Overlays
WDboolShow weekday bartrue/false
WDCAstr/[r,g,b]Active weekday color
WDCIstr/[r,g,b]Inactive weekday color
CELboolCelsius (false=Fahrenheit)true/false
SOMboolWeek starts Mondaytrue/false
BLOCKNboolBlock physical buttonstrue/false
MATPboolMatrix on/off (no animation)true/false
VOLintSpeaker/DFPlayer volume0–30
TIMboolEnable time app (reboot)true/false
DATboolEnable date app (reboot)true/false
HUMboolEnable humidity app (reboot)true/false
TEMPboolEnable temperature app (reboot)true/false
BATboolEnable battery app (reboot)true/false
CCORRECTION[r,g,b]Color correction
CTEMP[r,g,b]Color temperature
TIME_COLstr/[r,g,b]Time app text color (0=global)
DATE_COLstr/[r,g,b]Date app text color
TEMP_COLstr/[r,g,b]Temp app text color
HUM_COLstr/[r,g,b]Humidity app text color
BAT_COLstr/[r,g,b]Battery app text color
CHCOLstr/[r,g,b]Calendar header color
CBCOLstr/[r,g,b]Calendar body color
CTCOLstr/[r,g,b]Calendar text color
+ + +

Effects & Overlays — fetched live from device

+
+
+

Background Effects

+
Loading...
+
+
+

Overlay Effects

+
clear · snow · rain · drizzle · storm · thunder · frost
+
+
+

App Transitions

+
Loading...
+
+
+ + +

Draw Commands — "draw":[...] in notify/custom

+ + + + + + + + + + +
CommandValuesDescription
dp[x,y,color]Draw pixel
dl[x0,y0,x1,y1,color]Draw line
dr[x,y,w,h,color]Rectangle outline
df[x,y,w,h,color]Filled rectangle
dc[x,y,r,color]Circle outline
dfc[x,y,r,color]Filled circle
dt[x,y,"text",color]Draw text
db[x,y,w,h,[rgb888array]]Bitmap array
+
{"draw":[{"df":[0,0,8,8,"#1a1aff"]},{"dt":[9,1,"Hi","#ffffff"]}]}
+ + +

OSC (UDP port 4210)

+

Send OSC UDP packets to port 4210. Both bare addresses and /dpx_tc002/ or /awtrix/ namespace prefixes are accepted.

+ + + + + + + + + + +
AddressArgsAction
/notify or /text(s) textOne-shot notification
/custom/<name>(s) textUpdate/create persistent app
/switch(s) appnameSwitch to named app
/nextappnoneNext app
/previousappnonePrevious app
/power(i|f) 0/1Power off/on
/brightness(i|f) 0–255Set brightness
/indicator/1 /2 /3(i i i) r g bSet indicator color
+
# python-osc example +from pythonosc import udp_client +c = udp_client.SimpleUDPClient("192.168.x.x", 4210) +c.send_message("/notify", "01:23:45:12") +c.send_message("/dpx_tc002/custom/tc", "00:59:59:24")
+ + +

MQTT — broker configured in /setup · prefix set per device

+

All topics use your configured prefix (default: device hostname, e.g. awtrix_a1b2c3). Format: [PREFIX]/topic.

+ +

Inbound — device subscribes, you publish

+ + + + + + + + + + + + + + + + + + + + + + +
TopicPayloadAction
[PREFIX]/notifyJSONOne-shot notification — same JSON keys as HTTP notify
[PREFIX]/notify/dismissemptyDismiss held notification
[PREFIX]/custom/[appname]JSON or emptyCreate/update custom app; empty payload = delete
[PREFIX]/settingsJSONUpdate settings — same keys as HTTP settings
[PREFIX]/switch{"name":"Time"}Switch to named app
[PREFIX]/nextappanyNext app
[PREFIX]/previousappanyPrevious app
[PREFIX]/power{"power":true}Power on/off
[PREFIX]/sleep{"sleep":60}Deep sleep for N seconds
[PREFIX]/moodlightJSON or emptySet moodlight; empty = disable
[PREFIX]/indicator1{"color":[r,g,b],"blink":500}Indicator 1
[PREFIX]/indicator2sameIndicator 2
[PREFIX]/indicator3sameIndicator 3
[PREFIX]/sound{"sound":"alarm"}Play sound file from /MELODIES/
[PREFIX]/rtttlraw RTTTL stringPlay inline RTTTL melody
[PREFIX]/appsJSON arrayUpdate app loop order
[PREFIX]/sendscreenanyRequest device to publish current screen state
[PREFIX]/doupdateanyTrigger OTA firmware update
[PREFIX]/rebootanyReboot device
[PREFIX]/r2d2anyPlay R2D2 sound effect
+ +

Outbound — device publishes, you subscribe

+ + + + + + + + + + + +
TopicPayloadWhen
[PREFIX]/statsJSONPeriodic stats: battery, RAM, uptime, temp, humidity, lux, RSSI, IP, version
[PREFIX]/stats/currentAppstringApp name each time display switches
[PREFIX]/stats/effectsJSON arrayPublished on connect — list of effect names
[PREFIX]/stats/transitionsJSON arrayPublished on connect — list of transition names
[PREFIX]/stats/deviceonlinePublished on connect
[PREFIX]/screenJSON array (256× 24-bit int)Response to /sendscreen
[PREFIX]/buttonLefttrue/falsePhysical button press/release
[PREFIX]/buttonRighttrue/falsePhysical button press/release
[PREFIX]/buttonSelecttrue/falseMiddle button press/release
+ +
# mosquitto example — send notification +mosquitto_pub -h 192.168.x.x -t "awtrix_a1b2c3/notify" \ + -m '{"text":"hello","rainbow":true,"duration":8}' + +# create a persistent app +mosquitto_pub -h 192.168.x.x -t "awtrix_a1b2c3/custom/myticker" \ + -m '{"text":"LIVE","color":[255,0,0],"scrollSpeed":80}' + +# subscribe to button presses +mosquitto_sub -h 192.168.x.x -t "awtrix_a1b2c3/button+"
+ +
+ +)APIREF"; + +// ── Community Browser page (/browse) ───────────────────────────────────────── +// Three tabs: +// 1. LaMetric Icons – paginated grid of thumbnails loaded via (no CORS), +// one-click install to /ICONS/ on the device. Clicking any installed icon +// copies the usage snippet to the clipboard. +// 2. Bigtime GIFs – lists files from Blueforcer/awtrix3 on GitHub, one-click +// install to the device root (used by TMODE=5). +// 3. On-Device Files – lists /ICONS/, /MELODIES/, root; allows delete. +static const char browse_html[] PROGMEM = R"BROWSE( +Browse + +

☶ Browse & Install

+ + +
+
LaMetric Icons
+
Bigtime GIFs
+
On-Device Files
+
+ + +
+

Click Get to install an icon to the device. Once installed, click Use to copy its ID — paste it as the icon value in any notify/custom-app call.

+
+ + + | + + page + + + (50/page) +
+
+
+ + +
+

Official Bigtime GIFs — install to device root, then set TMODE=5 and name the file bigtime.gif.

+
Loading from GitHub...
+
+ + +
+
+

ICONS/

Loading...
+

MELODIES/

Loading...
+

Root

Loading...
+
+ +
+ +)BROWSE"; + +// Small snippet injected into /setup to link to the control panel +static const char ctrl_nav_html[] PROGMEM = R"EOF( + +)EOF"; + +static const char ctrl_html[] PROGMEM = R"EOF( +dpx_tc002 + +

■ dpx_tc002

+ +
+ +
+

Notification

+ +
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ + +
+
+ +
+

Custom App

+

A custom app lives permanently in the rotation loop alongside Time/Date/Temp — it cycles through automatically and stays until you remove it. A Notification (above) is one-shot: it interrupts once then vanishes.

+
+
+
+ + +
+
+
+ +
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ + + +
+
+ +
+

Indicators

+
+
+ 1 +
+
+
+ + +
+
+ 2 +
+
+
+ + +
+
+ 3 +
+
+
+ + +
+
+
+ +
+

Moodlight

+ +
+
+
+
+
+ +
+ + +
+
+ +
+

Display

+ +
128
+ +
+ +
+
+
+
+
+ + +
+
+ +
+
+ + +
+
+ +
+

App Channels

+

Each custom app is a named channel. The name is the OSC address and MQTT topic suffix — send to it from anywhere to update the display.

+
+ MQTT prefix loading... +
+
Loading...
+
+

Create Channel

+
+ + + +
+

After creating, push updates via OSC or MQTT using the channel name shown above.

+
+ +
+

OSC Listeners — map OSC paths to display channels

+

Register any OSC address. When a packet arrives the first argument is shown on the named channel. Use channel tc for timecode (triggers TC display mode).

+
+
+ + + +
+
+ + +
+
+ + +
+
+
+ +
+
Loading...
+
+ +
+

TC Settings

+

Controls how the timecode display behaves when LTC frames arrive via OSC.

+
+
+
+
+ + +
+
+
+
+ +
+ +
+

Native Apps

+

Toggle which built-in apps appear in the rotation. Changes take effect immediately.

+
+
+
+
+
+
+
+ +
+ +
+

Time

+

Device syncs via NTP on boot. Set manually if NTP is unavailable or time is wrong.

+ +
+ +
+ +
+ + +
+
+ +
+ + + +
+
+ + re-polls configured NTP server +
+
+ +
+

Sensors

+

Offsets apply immediately and persist across reboots. The ESP32's internal temp sensor runs hot — a negative offset around -9°C is typical.

+ +
+
+
+
+
+ + +
+
+
+
+ + +
+
+ +
+ +
+

Sound

+
+
+
+ +
+
+ +
+ +
+ +
+ + +
+
+ +
+ + + +
+
+ +
+
+ +)EOF"; + +static const char screenfull_html[] PROGMEM = R"EOF( + LiveView +)EOF"; \ No newline at end of file diff --git a/usermods/dpx_matrix/dpx_matrix.cpp b/usermods/dpx_matrix/dpx_matrix.cpp new file mode 100644 index 0000000000..5651307ed4 --- /dev/null +++ b/usermods/dpx_matrix/dpx_matrix.cpp @@ -0,0 +1,17 @@ +// ================================================================================ +// dpx_matrix.cpp — Usermod Entry Point +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_matrix.cpp +// Purpose: Includes wled.h (gives access to strip, server, bri, etc.) and then +// the full dpx_matrix usermod implementation. +// WLED's build system compiles this as a separate library and links it. +// +// ================================================================================ + +#include "wled.h" +#include "dpx_matrix.h" diff --git a/usermods/dpx_matrix/dpx_matrix.h b/usermods/dpx_matrix/dpx_matrix.h new file mode 100644 index 0000000000..111ce9a80a --- /dev/null +++ b/usermods/dpx_matrix/dpx_matrix.h @@ -0,0 +1,126 @@ +// ================================================================================ +// dpx_matrix.h — Main Usermod Class +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_matrix.h +// Purpose: WLED Usermod class that takes over the 32×8 LED matrix to display +// text apps, scrolling text, timecode, and notifications. Also registers +// custom HTTP API routes and an OSC UDP receiver. +// +// Activate in platformio_override.ini: +// custom_usermods = dpx_matrix +// +// WLED setup required (via WLED web UI or startup config): +// - LED Type: WS2812B (RGB) +// - GPIO: 32 +// - LED Count: 256 +// - 2D Matrix: width=32, height=8, serpentine=no +// +// ================================================================================ + +#pragma once + +// Include all module headers in dependency order +#include "dpx_font.h" +#include "dpx_text.h" +#include "dpx_persist.h" +#include "dpx_apps.h" +#include "dpx_notifications.h" +#include "dpx_tc.h" +#include "dpx_osc.h" +#include "dpx_api.h" + +class DpxMatrix : public Usermod { + +private: + bool _initDone = false; + + // Render the 3 indicator pixels (corner dots). + // Indicator 1 = top-left (pixel 0) + // Indicator 2 = top-right (pixel 31) + // Indicator 3 = bottom-left (pixel 224) + void renderIndicators() { + if (dpxIndicator[0]) strip.setPixelColor(0, dpxIndicator[0]); + if (dpxIndicator[1]) strip.setPixelColor(31, dpxIndicator[1]); + if (dpxIndicator[2]) strip.setPixelColor(224, dpxIndicator[2]); + } + +public: + static const char _name[]; + + void setup() override { + // Load persistent settings + dpxLoadDev(); + dpxLoadOscListeners(); + + // Build the initial app loop (Time, Date only to start) + dpxRebuildLoop(); + dpxAppStartMs = millis(); + + // Start UDP for OSC + dpxOscBegin(); + + // Register HTTP routes + dpxRegisterRoutes(); + + _initDone = true; + DEBUG_PRINTLN(F("DpxMatrix: setup complete")); + } + + void loop() override { + if (!_initDone) return; + + // Advance app pointer when duration expires + dpxAppLoopTick(); + + // TC dwell timeout — restore auto-transition after TC signal stops + dpxTcDwellTick(); + + // Receive OSC packets + dpxOscTick(); + } + + void handleOverlayDraw() override { + if (!_initDone) return; + + // Notifications take priority over the app loop + if (dpxNotifTick()) { + dpxRenderNotification(); + } else { + dpxRenderCurrentApp(); + } + + // Overlay indicator dots on top of everything + renderIndicators(); + } + + uint16_t getId() override { return USERMOD_ID_DPX_MATRIX; } + + void addToJsonInfo(JsonObject& root) override { + JsonObject user = root["u"].isNull() ? root.createNestedObject("u") : root["u"]; + user[FPSTR(_name)] = F("dpx_tc002 matrix active"); + } + + // ── Usermod settings persist (WLED /cfg.json) ───────────────────────── + void addToConfig(JsonObject& root) override { + JsonObject top = root.createNestedObject(FPSTR(_name)); + top["atime"] = DPX_ATIME; + top["atrans"] = DPX_ATRANS; + top["sspeed"] = DPX_SSPEED; + } + + bool readFromConfig(JsonObject& root) override { + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) return false; + if (top.containsKey("atime")) DPX_ATIME = top["atime"]; + if (top.containsKey("atrans")) DPX_ATRANS = top["atrans"]; + if (top.containsKey("sspeed")) DPX_SSPEED = top["sspeed"]; + return true; + } +}; + +const char DpxMatrix::_name[] PROGMEM = "DpxMatrix"; diff --git a/usermods/dpx_matrix/dpx_mqtt.h b/usermods/dpx_matrix/dpx_mqtt.h new file mode 100644 index 0000000000..73c08be322 --- /dev/null +++ b/usermods/dpx_matrix/dpx_mqtt.h @@ -0,0 +1,208 @@ +// ================================================================================ +// dpx_mqtt.h — MQTT Integration +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_mqtt.h +// Purpose: Subscribe to dpx/# topics and dispatch to dpx_matrix modules. +// Uses WLED's existing AsyncMqttClient connection (global `mqtt`). +// +// Topic convention — subscribe root is: {mqttDeviceTopic}/dpx/# +// (e.g. "wled/AABBCCDDEEFF/dpx/#") +// Also accepts the short alias "dpx/#" for compatibility with dpx_tc001 senders. +// +// Supported topics (payload is JSON unless noted): +// .../dpx/notify → push notification {"text":"...","duration":5} +// .../dpx/notify/dismiss → dismiss active notification (payload ignored) +// .../dpx/tc → timecode string "HH:MM:SS:FF" (plain text or JSON) +// .../dpx/switch → switch to app {"name":"clock"} or plain app name +// .../dpx/nextapp → advance app loop (payload ignored) +// .../dpx/previousapp → step back in app loop (payload ignored) +// .../dpx/app/ → create/update custom app by name +// .../dpx/indicator/<1-3> → set indicator pixel {"color":[r,g,b]} or "" to clear +// .../dpx/power → {"power":true/false} +// .../dpx/brightness → {"bri":128} (0–255) +// .../dpx/rtttl → raw RTTTL string or JSON {"rtttl":"..."} — "stop" silences +// +// ================================================================================ + +#pragma once +#include "dpx_apps.h" +#include "dpx_notifications.h" +#include "dpx_tc.h" +#include "dpx_overlay.h" + +// dpxIndicator is defined in dpx_matrix.cpp; declared extern in dpx_osc.h +extern uint32_t dpxIndicator[3]; + +// Relative sub-path we attach to mqttDeviceTopic. Must match what senders use. +static const char DPX_MQTT_SUB[] PROGMEM = "/dpx/#"; +// Short alias accepted regardless of device topic (for cross-device compatibility) +static const char DPX_MQTT_ALIAS[] PROGMEM = "dpx/#"; + +// ── Internal helpers ────────────────────────────────────────────────────────── + +// Strip the leading topic prefix and return the command portion ("dpx/cmd"). +// Returns empty String if topic doesn't look like ours. +static String dpxMqttCmd(const char* topic) { + String t(topic); + // Match either "{mqttDeviceTopic}/dpx/..." or "dpx/..." + String dev = String(mqttDeviceTopic) + F("/dpx/"); + if (t.startsWith(dev)) return t.substring(dev.length()); + if (t.startsWith(F("dpx/"))) return t.substring(4); + return ""; +} + +// ── Public API ──────────────────────────────────────────────────────────────── + +// Call from DpxMatrix::onMqttConnect() +static void dpxMqttConnect() { + if (!WLED_MQTT_CONNECTED) return; + // Per-device topic: wled/MAC/dpx/# + String sub = String(mqttDeviceTopic) + "/dpx/#"; + mqtt->subscribe(sub.c_str(), 0); + // Alias: dpx/# (compatible with dpx_tc001 senders) + mqtt->subscribe("dpx/#", 0); + DEBUG_PRINTF("DpxMatrix: MQTT subscribed to %s and dpx/#\n", sub.c_str()); +} + +// Call from DpxMatrix::onMqttMessage(). Returns true if topic was ours. +static bool dpxMqttMessage(char* topic, char* payload) { + String cmd = dpxMqttCmd(topic); + if (!cmd.length()) return false; + + // ── notify ────────────────────────────────────────────────────────────── + if (cmd == F("notify")) { + dpxPushNotification(payload); + return true; + } + if (cmd == F("notify/dismiss")) { + dpxDismissNotification(); + return true; + } + + // ── timecode ───────────────────────────────────────────────────────────── + if (cmd == F("tc")) { + String tc(payload); + tc.trim(); + // Accept plain "HH:MM:SS:FF" or JSON {"tc":"HH:MM:SS:FF"} + if (tc.startsWith("{")) { + StaticJsonDocument<64> doc; + if (!deserializeJson(doc, tc) && doc.containsKey("tc")) + tc = doc["tc"].as(); + } + if (tc.length() >= 8) dpxPushTC(tc); + return true; + } + + // ── app loop control ────────────────────────────────────────────────────── + if (cmd == F("nextapp")) { dpxNextApp(); return true; } + if (cmd == F("previousapp")) { dpxPrevApp(); return true; } + + if (cmd == F("switch")) { + String p(payload); p.trim(); + // Accept plain name or {"name":"..."} + if (!p.startsWith("{")) { + StaticJsonDocument<64> doc; + doc["name"] = p; + String s; serializeJson(doc, s); + dpxSwitchToApp(s.c_str()); + } else { + dpxSwitchToApp(p.c_str()); + } + return true; + } + + // ── custom app upsert ───────────────────────────────────────────────────── + // topic: .../dpx/app/ + if (cmd.startsWith(F("app/"))) { + String name = cmd.substring(4); + if (name.length()) dpxSetCustomApp(name, payload); + return true; + } + + // ── indicator pixels ───────────────────────────────────────────────────── + // topic: .../dpx/indicator/1 (or 2, 3) + if (cmd.startsWith(F("indicator/"))) { + int num = cmd.charAt(10) - '0'; + if (num >= 1 && num <= 3) { + String p(payload); p.trim(); + if (!p.length() || p == "0" || p == "off") { + dpxIndicator[num - 1] = 0; + } else { + StaticJsonDocument<128> doc; + if (!deserializeJson(doc, p) && doc.containsKey("color")) { + JsonArray a = doc["color"].as(); + if (a.size() >= 3) + dpxIndicator[num - 1] = ((uint32_t)(uint8_t)a[0] << 16) + | ((uint32_t)(uint8_t)a[1] << 8) + | (uint32_t)(uint8_t)a[2]; + } + } + } + return true; + } + + // ── power / brightness ──────────────────────────────────────────────────── + if (cmd == F("power")) { + StaticJsonDocument<64> doc; + if (!deserializeJson(doc, payload) && doc.containsKey("power")) { + bool on = doc["power"].as(); + bri = on ? (briLast > 0 ? briLast : 128) : 0; + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + return true; + } + if (cmd == F("brightness")) { + StaticJsonDocument<64> doc; + String p(payload); p.trim(); + if (p.length() && isDigit(p[0])) { + bri = (uint8_t)p.toInt(); + } else if (!deserializeJson(doc, p) && doc.containsKey("bri")) { + bri = doc["bri"].as(); + } + stateUpdated(CALL_MODE_DIRECT_CHANGE); + return true; + } + + // ── RTTTL / buzzer ──────────────────────────────────────────────────────── + // topic: .../dpx/rtttl payload: raw RTTTL string or JSON {"rtttl":"..."} + if (cmd == F("rtttl")) { + String p(payload); p.trim(); + if (!p.length() || p == "stop") { + dpxBuzzerStop(); + } else if (p.startsWith("{")) { + StaticJsonDocument<256> doc; + if (!deserializeJson(doc, p) && doc.containsKey("rtttl")) + dpxBuzzerPlay(doc["rtttl"].as()); + } else { + dpxBuzzerPlay(p.c_str()); + } + return true; + } + + // ── Text overlay ────────────────────────────────────────────────────────── + if (cmd == F("overlay")) { + String p(payload); p.trim(); + if (!p.length() || p == "0" || p == "off" || p == "clear") + dpxClearOverlay(); + else + dpxSetOverlay(p.c_str()); + return true; + } + + // ── Pixel effect ────────────────────────────────────────────────────────── + if (cmd == F("effect")) { + String p(payload); p.trim(); + if (!p.length() || p == "none" || p == "off" || p == "clear") + dpxClearPixelEffect(); + else + dpxSetPixelEffect(p.c_str()); + return true; + } + + return false; // not our topic +} diff --git a/usermods/dpx_matrix/dpx_notifications.h b/usermods/dpx_matrix/dpx_notifications.h new file mode 100644 index 0000000000..85ce34625e --- /dev/null +++ b/usermods/dpx_matrix/dpx_notifications.h @@ -0,0 +1,86 @@ +// ================================================================================ +// dpx_notifications.h — Notification Queue +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_notifications.h +// Purpose: One-shot notifications that interrupt the app loop, display once, +// then vanish (or hold until dismissed if hold=true). +// +// ================================================================================ + +#pragma once +#include "dpx_apps.h" + +struct DpxNotification { + DpxCustomApp data; + bool hold = false; // true = hold until explicit dismiss + bool stack = true; // true = queue, false = replace current +}; + +static std::vector dpxNotifQueue; +static bool dpxNotifActive = false; +static DpxNotification dpxCurrentNotif; +static unsigned long dpxNotifStartMs = 0; + +// Parse and enqueue a notification from JSON body (SPEC.md §5 POST /api/notify) +static bool dpxPushNotification(const char* json) { + DynamicJsonDocument doc(1024); + if (deserializeJson(doc, json)) return false; + + DpxNotification notif; + notif.data = dpxParseApp(json); + if (!notif.data.valid) { + // Minimal: just a text string + notif.data.valid = true; + notif.data.text = doc["text"].as(); + } + notif.hold = doc.containsKey("hold") ? doc["hold"].as() : false; + notif.stack = doc.containsKey("stack") ? doc["stack"].as() : true; + + if (!notif.stack) { + // Replace: clear queue and active + dpxNotifQueue.clear(); + dpxNotifActive = false; + } + dpxNotifQueue.push_back(notif); + return true; +} + +// Dismiss the currently active held notification +static void dpxDismissNotification() { + dpxNotifActive = false; + dpxNotifQueue.erase(dpxNotifQueue.begin(), dpxNotifQueue.end()); +} + +// Notification tick — call from loop() after app tick +// Returns true while a notification is being displayed. +static bool dpxNotifTick() { + if (!dpxNotifActive) { + if (dpxNotifQueue.empty()) return false; + dpxCurrentNotif = dpxNotifQueue.front(); + dpxNotifQueue.erase(dpxNotifQueue.begin()); + dpxNotifActive = true; + dpxNotifStartMs = millis(); + dpxScroll.stop(); + } + + // Check duration expiry (hold notifications never auto-dismiss) + if (!dpxCurrentNotif.hold) { + unsigned long dur = dpxCurrentNotif.data.durationMs(); + if (dur == 0) dur = 5000; // default 5s + if (millis() - dpxNotifStartMs >= dur) { + dpxNotifActive = false; + return false; + } + } + return true; +} + +// Render the current notification (call from handleOverlayDraw() when notifTick() = true) +static void dpxRenderNotification() { + dpxRenderApp(dpxCurrentNotif.data); +} diff --git a/usermods/dpx_matrix/dpx_osc.h b/usermods/dpx_matrix/dpx_osc.h new file mode 100644 index 0000000000..b8e1591982 --- /dev/null +++ b/usermods/dpx_matrix/dpx_osc.h @@ -0,0 +1,237 @@ +// ================================================================================ +// dpx_osc.h — OSC Receiver (UDP port 4210) +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// Ported/adapted from dpx_tc001 ServerManager.cpp::handleOSC() +// (original work — OSC protocol handling, not AWTRIX-derived) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_osc.h +// Purpose: Receives OSC packets on UDP port 4210. Handles built-in addresses +// and routes unknown addresses through the OSC Listener Registry +// (d3 disguise integration). FIND_AWTRIX discovery also handled here. +// +// Supported addresses (both bare and /dpx_tc002/ or /awtrix/ prefixed): +// /notify, /text, /tc, /custom/, /switch, +// /nextapp, /previousapp, /power, /brightness, +// /indicator/1, /indicator/2, /indicator/3 +// +// ================================================================================ + +#pragma once +#include +#include +#include "dpx_tc.h" +#include "dpx_notifications.h" + +static WiFiUDP dpxUdp; +static const uint16_t DPX_OSC_PORT = 4210; +static bool dpxUdpStarted = false; + +// ── OSC binary helpers ──────────────────────────────────────────────────────── +static String dpxOscStr(const uint8_t* b, int& p, int len) { + String s; + while (p < len && b[p]) s += (char)b[p++]; + p++; // consume null terminator + p = (p + 3) & ~3; // pad to 4-byte boundary + return s; +} + +static int32_t dpxOscI32(const uint8_t* b, int& p) { + int32_t v = ((int32_t)b[p] << 24) | ((int32_t)b[p+1] << 16) + | ((int32_t)b[p+2] << 8) | (int32_t)b[p+3]; + p += 4; + return v; +} + +static float dpxOscF32(const uint8_t* b, int& p) { + uint32_t raw = ((uint32_t)b[p] << 24) | ((uint32_t)b[p+1] << 16) + | ((uint32_t)b[p+2] << 8) | (uint32_t)b[p+3]; + p += 4; + float f; + memcpy(&f, &raw, sizeof f); + return f; +} + +static int dpxOscNum(const uint8_t* b, int& p, char tag) { + if (tag == 'f') return (int)dpxOscF32(b, p); + return (int)dpxOscI32(b, p); +} + +// ── OSC Listener Registry — persist ────────────────────────────────────────── +static void dpxSaveOscListeners() { + DynamicJsonDocument doc(2048); + JsonArray arr = doc.to(); + for (auto& lsr : dpxOscListeners) { + JsonObject o = arr.createNestedObject(); + o["path"] = lsr.path; o["channel"] = lsr.channel; o["label"] = lsr.label; + } + File f = LittleFS.open("/osc_listeners.json", "w"); + if (f) { serializeJson(doc, f); f.close(); } +} + +static void dpxLoadOscListeners() { + if (!LittleFS.exists("/osc_listeners.json")) return; + File f = LittleFS.open("/osc_listeners.json", "r"); + if (!f) return; + DynamicJsonDocument doc(2048); + if (deserializeJson(doc, f)) { f.close(); return; } + f.close(); + dpxOscListeners.clear(); + for (JsonObject o : doc.as()) { + DpxOscListener lsr; + lsr.path = o["path"].as(); + lsr.channel = o["channel"].as(); + lsr.label = o.containsKey("label") ? o["label"].as() : lsr.channel; + if (!lsr.path.isEmpty() && !lsr.channel.isEmpty()) + dpxOscListeners.push_back(lsr); + } +} + +static String dpxOscListenersJson() { + DynamicJsonDocument doc(2048); + JsonArray arr = doc.to(); + for (auto& lsr : dpxOscListeners) { + JsonObject o = arr.createNestedObject(); + o["path"] = lsr.path; o["channel"] = lsr.channel; o["label"] = lsr.label; + } + String s; serializeJson(doc, s); return s; +} + +// ── Main OSC dispatch ───────────────────────────────────────────────────────── +static void dpxHandleOSC(const uint8_t* buf, int len) { + if (len < 4 || buf[0] != '/') return; + int pos = 0; + String addr = dpxOscStr(buf, pos, len); + if (pos >= len || buf[pos] != ',') return; + String tags = dpxOscStr(buf, pos, len); // tags[0] == ',' + + // Accept /dpx_tc002/... as primary; /dpx_tc001/ and /awtrix/ for compatibility + if (addr.startsWith("/dpx_tc002")) addr = addr.substring(10); + else if (addr.startsWith("/dpx_tc001")) addr = addr.substring(10); + else if (addr.startsWith("/awtrix")) addr = addr.substring(7); + if (addr.isEmpty()) addr = "/"; + + if (addr == "/tc") { + if (tags.length() >= 2 && tags[1] == 's') { + String tc = dpxOscStr(buf, pos, len); + dpxPushTC(tc); + } + } else if (addr == "/notify" || addr == "/text") { + if (tags.length() >= 2 && tags[1] == 's') { + String text = dpxOscStr(buf, pos, len); + StaticJsonDocument<256> doc; + doc["text"] = text; + String json; serializeJson(doc, json); + dpxPushNotification(json.c_str()); + } + } else if (addr.startsWith("/custom/")) { + String name = addr.substring(8); + if (!name.isEmpty() && tags.length() >= 2 && tags[1] == 's') { + String text = dpxOscStr(buf, pos, len); + if (name == "tc") { + dpxPushTC(text); + } else { + StaticJsonDocument<256> doc; + doc["text"] = text; + String json; serializeJson(doc, json); + dpxSetCustomApp(name, json.c_str()); + } + } + } else if (addr == "/switch") { + if (tags.length() >= 2 && tags[1] == 's') { + String name = dpxOscStr(buf, pos, len); + StaticJsonDocument<128> doc; + doc["name"] = name; + String json; serializeJson(doc, json); + dpxSwitchToApp(json.c_str()); + } + } else if (addr == "/nextapp") { dpxNextApp(); } + else if (addr == "/previousapp") { dpxPrevApp(); } + else if (addr == "/power") { + if (tags.length() >= 2) { + bool on = (dpxOscNum(buf, pos, tags[1]) != 0); + if (!on) { + // Turn WLED off + bri = 0; + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } else { + bri = briLast > 0 ? briLast : 128; + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + } + } else if (addr == "/brightness") { + if (tags.length() >= 2) { + int b = constrain(dpxOscNum(buf, pos, tags[1]), 0, 255); + bri = b; + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + } else if (addr.startsWith("/indicator/")) { + // Indicator dots — stored as corner pixels + int num = addr.substring(11).toInt(); + if (num >= 1 && num <= 3 && tags.length() >= 4) { + int r = constrain(dpxOscNum(buf, pos, tags[1]), 0, 255); + int g = constrain(dpxOscNum(buf, pos, tags[2]), 0, 255); + int b = constrain(dpxOscNum(buf, pos, tags[3]), 0, 255); + // Store indicator colors (rendered in handleOverlayDraw) + // Indicator 1 = pixel 0 (top-left), 2 = pixel 31, 3 = pixel 224 + uint32_t col = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; + extern uint32_t dpxIndicator[3]; + if (num >= 1 && num <= 3) dpxIndicator[num - 1] = col; + } + } else { + // Dynamic OSC listener registry (d3 monitoring paths) + for (auto& lsr : dpxOscListeners) { + if (addr == lsr.path && tags.length() >= 2) { + String val; + char t = tags[1]; + if (t == 's') val = dpxOscStr(buf, pos, len); + else if (t == 'f') val = String(dpxOscF32(buf, pos), 4); + else if (t == 'i') val = String(dpxOscI32(buf, pos)); + if (lsr.channel == "tc") { + dpxPushTC(val); + } else { + StaticJsonDocument<256> doc; + doc["text"] = val; + String json; serializeJson(doc, json); + dpxSetCustomApp(lsr.channel, json.c_str()); + } + break; + } + } + } +} + +// ── UDP receive tick — call from loop() ─────────────────────────────────────── +#define DPX_UDP_BUF 512 +static char dpxUdpBuf[DPX_UDP_BUF]; + +static void dpxOscTick() { + if (!dpxUdpStarted) return; + int pkt = dpxUdp.parsePacket(); + if (!pkt) return; + int len = dpxUdp.read(dpxUdpBuf, DPX_UDP_BUF - 1); + if (len <= 0) return; + dpxUdpBuf[len] = 0; + + if (dpxUdpBuf[0] == '/') { + // OSC packet + dpxHandleOSC((const uint8_t*)dpxUdpBuf, len); + } else if (strcmp(dpxUdpBuf, "FIND_AWTRIX") == 0) { + // Discovery response — reply on port 4211 with hostname:port + char resp[64]; + snprintf(resp, sizeof(resp), "%s", WiFi.getHostname()); + dpxUdp.beginPacket(dpxUdp.remoteIP(), 4211); + dpxUdp.write((const uint8_t*)resp, strlen(resp)); + dpxUdp.endPacket(); + } +} + +// ── Start UDP listener ──────────────────────────────────────────────────────── +static void dpxOscBegin() { + if (dpxUdpStarted) return; + dpxUdp.begin(DPX_OSC_PORT); + dpxUdpStarted = true; +} diff --git a/usermods/dpx_matrix/dpx_overlay.h b/usermods/dpx_matrix/dpx_overlay.h new file mode 100644 index 0000000000..d4437a6d92 --- /dev/null +++ b/usermods/dpx_matrix/dpx_overlay.h @@ -0,0 +1,242 @@ +// ================================================================================ +// dpx_overlay.h — Text Overlay + Pixel Effects (run on top of app content) +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_overlay.h +// Purpose: Two stacked layers rendered after dpxRenderCurrentApp(): +// +// 1. TEXT OVERLAY — static or scrolling text drawn at a specific position +// over the current app content. Controlled via MQTT dpx/overlay or +// JSON state {"dpx":{"overlay":{...}}}. +// +// Position options: +// "top" → baseline row 2 (glyph rows 1–5, occupies top of display) +// "bottom" → baseline row 7 (glyph rows 3–7, occupies bottom 5 rows) +// "center" → baseline DPX_FONT_BASELINE (vertically centered) +// N (int) → explicit baseline row number +// +// JSON schema: +// {"text":"LIVE","color":"#FF0000","pos":"top","scroll":false,"speed":80} +// Clear: {"text":""} +// +// 2. PIXEL EFFECT — lightweight per-pixel effect applied on top of everything. +// Controlled via MQTT dpx/effect or JSON state {"dpx":{"effect":{...}}}. +// +// Effects: "sparkle", "strobe", "rain", "twinkle", "blink", "none" +// +// JSON schema: +// {"name":"sparkle","color":"#FFFFFF","intensity":50} +// Clear: {"name":"none"} or {"name":""} +// +// ================================================================================ + +#pragma once +#include "dpx_text.h" +#include "dpx_apps.h" // for dpxParseColor + +// ── Text overlay state ──────────────────────────────────────────────────────── +static struct { + bool active = false; + String text; + uint32_t color = 0xFFFFFF; + bool rainbow = false; + bool scroll = false; + int baseline = DPX_FONT_BASELINE; // cursor_y + int speed = 80; // scroll speed % + // Scroll state (re-used from DpxScrollState internals inline): + int scrollX = DPX_MATRIX_W; + int textWidth = 0; + unsigned long lastMs = 0; + int speedMs = 50; +} dpxTextOverlay; + +static struct { + String name; // "sparkle", "strobe", "rain", "twinkle", "blink", "none" + uint32_t color = 0xFFFFFF; + uint8_t intensity = 50; // 0–100 + bool active = false; + // per-effect private state + unsigned long lastMs = 0; + bool strobeOn = true; + uint8_t rain[DPX_MATRIX_W] = {}; // rain column heights +} dpxPixelEffect; + +// ── Text overlay control ────────────────────────────────────────────────────── + +static bool dpxSetOverlay(const char* json) { + StaticJsonDocument<256> doc; + if (deserializeJson(doc, json)) return false; + + String text = doc["text"] | String(); + if (!text.length()) { + dpxTextOverlay.active = false; + return true; + } + + dpxTextOverlay.text = text; + dpxTextOverlay.color = dpxParseColor(doc["color"], 0xFFFFFF); + dpxTextOverlay.rainbow = doc["rainbow"] | false; + dpxTextOverlay.scroll = doc["scroll"] | false; + dpxTextOverlay.speed = doc["speed"] | 80; + dpxTextOverlay.speedMs = max(10, (int)(50 * 100 / max(1, dpxTextOverlay.speed))); + dpxTextOverlay.textWidth = dpxTextPixelWidth(text.c_str()); + dpxTextOverlay.scrollX = DPX_MATRIX_W; + dpxTextOverlay.lastMs = 0; + + // Resolve position string → baseline row + if (doc.containsKey("pos")) { + JsonVariant pos = doc["pos"]; + if (pos.is()) { + dpxTextOverlay.baseline = pos.as(); + } else { + String p = pos.as(); + if (p == "top") dpxTextOverlay.baseline = 2; + else if (p == "bottom") dpxTextOverlay.baseline = 7; + else if (p == "center") dpxTextOverlay.baseline = DPX_FONT_BASELINE; + else dpxTextOverlay.baseline = DPX_FONT_BASELINE; + } + } else { + dpxTextOverlay.baseline = DPX_FONT_BASELINE; + } + + dpxTextOverlay.active = true; + return true; +} + +static void dpxClearOverlay() { dpxTextOverlay.active = false; } + +// Render text overlay — called after app/notification content is drawn. +static void dpxRenderTextOverlay() { + if (!dpxTextOverlay.active) return; + + if (!dpxTextOverlay.scroll || dpxTextOverlay.textWidth <= DPX_MATRIX_W) { + // Static: centre or left-align + int x = 0; + if (dpxTextOverlay.textWidth < DPX_MATRIX_W) + x = (DPX_MATRIX_W - dpxTextOverlay.textWidth) / 2; + dpxRenderText(x, dpxTextOverlay.baseline, + dpxTextOverlay.text.c_str(), + dpxTextOverlay.color, dpxTextOverlay.rainbow); + } else { + // Scrolling + unsigned long now = millis(); + if (now - dpxTextOverlay.lastMs >= (unsigned long)dpxTextOverlay.speedMs) { + dpxTextOverlay.lastMs = now; + if (--dpxTextOverlay.scrollX < -(dpxTextOverlay.textWidth)) + dpxTextOverlay.scrollX = DPX_MATRIX_W; + } + dpxRenderText(dpxTextOverlay.scrollX, dpxTextOverlay.baseline, + dpxTextOverlay.text.c_str(), + dpxTextOverlay.color, dpxTextOverlay.rainbow); + } +} + +// ── Pixel effect control ────────────────────────────────────────────────────── + +static bool dpxSetPixelEffect(const char* json) { + StaticJsonDocument<128> doc; + if (deserializeJson(doc, json)) return false; + + String name = doc["name"] | String("none"); + name.toLowerCase(); + dpxPixelEffect.name = name; + dpxPixelEffect.color = dpxParseColor(doc["color"], 0xFFFFFF); + dpxPixelEffect.intensity = doc["intensity"] | 50; + dpxPixelEffect.active = (name != "none" && name.length() > 0); + dpxPixelEffect.lastMs = 0; + dpxPixelEffect.strobeOn = true; + memset(dpxPixelEffect.rain, 0, sizeof(dpxPixelEffect.rain)); + return true; +} + +static void dpxClearPixelEffect() { dpxPixelEffect.active = false; } + +// Render one frame of the active pixel effect on top of current LED content. +static void dpxRenderPixelEffect() { + if (!dpxPixelEffect.active) return; + + unsigned long now = millis(); + uint32_t col = dpxPixelEffect.color; + uint8_t iv = dpxPixelEffect.intensity; + + // ── Sparkle ──────────────────────────────────────────────────────────── + if (dpxPixelEffect.name == "sparkle") { + // Each frame, light up ~intensity/4 random pixels white then fade + int count = max(1, (int)(iv / 4)); + for (int i = 0; i < count; i++) { + int px = (int)(random(256)); + strip.setPixelColor(px, col); + } + } + + // ── Twinkle ──────────────────────────────────────────────────────────────── + else if (dpxPixelEffect.name == "twinkle") { + int count = max(1, (int)(iv / 8)); + for (int i = 0; i < count; i++) { + int px = (int)(random(256)); + // Blend with existing pixel + uint32_t existing = strip.getPixelColor(px); + strip.setPixelColor(px, color_blend(existing, col, 180)); + } + } + + // ── Strobe ──────────────────────────────────────────────────────────── + else if (dpxPixelEffect.name == "strobe") { + // Flash on/off at speed derived from intensity + int intervalMs = map(iv, 0, 100, 400, 40); + if (now - dpxPixelEffect.lastMs >= (unsigned long)intervalMs) { + dpxPixelEffect.lastMs = now; + dpxPixelEffect.strobeOn = !dpxPixelEffect.strobeOn; + } + if (dpxPixelEffect.strobeOn) { + for (int i = 0; i < 256; i++) + strip.setPixelColor(i, color_blend(strip.getPixelColor(i), col, 200)); + } + } + + // ── Blink ───────────────────────────────────────────────────────────── + else if (dpxPixelEffect.name == "blink") { + int intervalMs = map(iv, 0, 100, 1000, 200); + if (now - dpxPixelEffect.lastMs >= (unsigned long)intervalMs) { + dpxPixelEffect.lastMs = now; + dpxPixelEffect.strobeOn = !dpxPixelEffect.strobeOn; + } + if (!dpxPixelEffect.strobeOn) { + for (int i = 0; i < 256; i++) strip.setPixelColor(i, 0); + } + } + + // ── Rain ────────────────────────────────────────────────────────────── + else if (dpxPixelEffect.name == "rain") { + int intervalMs = map(iv, 0, 100, 200, 20); + if (now - dpxPixelEffect.lastMs >= (unsigned long)intervalMs) { + dpxPixelEffect.lastMs = now; + // Advance each column's raindrop + for (int x = 0; x < DPX_MATRIX_W; x++) { + if (dpxPixelEffect.rain[x] > 0) { + // Erase old head, draw new + int y = dpxPixelEffect.rain[x] - 1; + if (y < DPX_MATRIX_H) dpxSetPixel(x, y, 0); + dpxPixelEffect.rain[x]++; + if ((int)dpxPixelEffect.rain[x] - 1 < DPX_MATRIX_H) + dpxSetPixel(x, dpxPixelEffect.rain[x] - 1, col); + if ((int)dpxPixelEffect.rain[x] > DPX_MATRIX_H + 1) + dpxPixelEffect.rain[x] = 0; // reset column + } + // Randomly start new drops + if (dpxPixelEffect.rain[x] == 0 && (random(256) < (iv * 2))) + dpxPixelEffect.rain[x] = 1; + } + } + } +} + +// ── Master overlay render — call at end of handleOverlayDraw() ──────────────── +static void dpxRenderOverlays() { + dpxRenderPixelEffect(); // pixel effect first (under text) + dpxRenderTextOverlay(); // text on top +} diff --git a/usermods/dpx_matrix/dpx_persist.h b/usermods/dpx_matrix/dpx_persist.h new file mode 100644 index 0000000000..6d25fd278b --- /dev/null +++ b/usermods/dpx_matrix/dpx_persist.h @@ -0,0 +1,107 @@ +// ================================================================================ +// dpx_persist.h — Persistent Settings (dev.json) + Runtime Globals +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_persist.h +// Purpose: Runtime configuration variables loaded from /dev.json on LittleFS. +// Also provides load/save helpers. Included once via dpx_matrix.cpp. +// +// dev.json keys: +// hostname, temp_offset, hum_offset, tc_dwell, tc_hold, tc_show_frames, +// min_brightness, max_brightness, ldr_factor, ldr_gamma, rotate_screen, +// mirror_screen, sensor_reading, matrix, dfplayer, bootsound, web_port, +// background_effect, ha_prefix, stats_interval +// +// ================================================================================ + +#pragma once +// ArduinoJson is pulled in via wled.h — do not include it directly here. +#include + +// ── Runtime variables (set at boot from dev.json, some apply immediately) ───── +static float DPX_TEMP_OFFSET = -9.0f; +static float DPX_HUM_OFFSET = 0.0f; +static uint32_t DPX_TC_DWELL_MS = 2000; // ms before TC app auto-dismiss +static bool DPX_TC_HOLD = false; // if true, TC never auto-dismisses +static bool DPX_TC_SHOW_FRAMES = false; // false=HH:MM:SS+bar, true=MM:SS.FF +static int DPX_MIN_BRI = 2; +static int DPX_MAX_BRI = 180; +static float DPX_LDR_FACTOR = 1.0f; +static float DPX_LDR_GAMMA = 3.0f; +static bool DPX_ROTATE_SCREEN = false; +static bool DPX_MIRROR_SCREEN = false; +static bool DPX_SENSOR_READING = true; +static int DPX_ATIME = 7; // app display seconds +static bool DPX_ATRANS = true; // auto-advance apps +static int DPX_SSPEED = 100; // global scroll speed % +static bool DPX_UPPERCASE = true; // force uppercase text + +// ── Load dev.json from LittleFS ─────────────────────────────────────────────── +static void dpxLoadDev() { + if (!LittleFS.exists("/dev.json")) return; + File f = LittleFS.open("/dev.json", "r"); + if (!f) return; + DynamicJsonDocument doc(1024); + if (deserializeJson(doc, f)) { f.close(); return; } + f.close(); + + if (doc.containsKey("temp_offset")) DPX_TEMP_OFFSET = doc["temp_offset"].as(); + if (doc.containsKey("hum_offset")) DPX_HUM_OFFSET = doc["hum_offset"].as(); + if (doc.containsKey("tc_dwell")) DPX_TC_DWELL_MS = (uint32_t)(doc["tc_dwell"].as() * 1000); + if (doc.containsKey("tc_hold")) DPX_TC_HOLD = doc["tc_hold"].as(); + if (doc.containsKey("tc_show_frames")) DPX_TC_SHOW_FRAMES = doc["tc_show_frames"].as(); + if (doc.containsKey("min_brightness")) DPX_MIN_BRI = doc["min_brightness"].as(); + if (doc.containsKey("max_brightness")) DPX_MAX_BRI = doc["max_brightness"].as(); + if (doc.containsKey("ldr_factor")) DPX_LDR_FACTOR = doc["ldr_factor"].as(); + if (doc.containsKey("ldr_gamma")) DPX_LDR_GAMMA = doc["ldr_gamma"].as(); + if (doc.containsKey("rotate_screen")) DPX_ROTATE_SCREEN = doc["rotate_screen"].as(); + if (doc.containsKey("mirror_screen")) DPX_MIRROR_SCREEN = doc["mirror_screen"].as(); + if (doc.containsKey("sensor_reading")) DPX_SENSOR_READING = doc["sensor_reading"].as(); +} + +// ── Merge a JSON object into dev.json and apply immediately ─────────────────── +// Returns false on parse error. +static bool dpxMergeDev(const char* json) { + DynamicJsonDocument incoming(512); + if (deserializeJson(incoming, json)) return false; + + DynamicJsonDocument merged(1024); + if (LittleFS.exists("/dev.json")) { + File f = LittleFS.open("/dev.json", "r"); + if (f) { deserializeJson(merged, f); f.close(); } + } + for (JsonPair kv : incoming.as()) + merged[kv.key()] = kv.value(); + + File fw = LittleFS.open("/dev.json", "w"); + if (!fw) return false; + serializeJson(merged, fw); + fw.close(); + + // Apply changed values immediately + if (incoming.containsKey("temp_offset")) DPX_TEMP_OFFSET = incoming["temp_offset"].as(); + if (incoming.containsKey("hum_offset")) DPX_HUM_OFFSET = incoming["hum_offset"].as(); + if (incoming.containsKey("tc_dwell")) DPX_TC_DWELL_MS = (uint32_t)(incoming["tc_dwell"].as() * 1000); + if (incoming.containsKey("tc_hold")) DPX_TC_HOLD = incoming["tc_hold"].as(); + if (incoming.containsKey("tc_show_frames")) DPX_TC_SHOW_FRAMES = incoming["tc_show_frames"].as(); + if (incoming.containsKey("min_brightness")) DPX_MIN_BRI = incoming["min_brightness"].as(); + if (incoming.containsKey("max_brightness")) DPX_MAX_BRI = incoming["max_brightness"].as(); + if (incoming.containsKey("ldr_factor")) DPX_LDR_FACTOR = incoming["ldr_factor"].as(); + if (incoming.containsKey("ldr_gamma")) DPX_LDR_GAMMA = incoming["ldr_gamma"].as(); + + return true; +} + +// ── Read dev.json as a String ───────────────────────────────────────────────── +static String dpxReadDevJson() { + if (!LittleFS.exists("/dev.json")) return F("{}"); + File f = LittleFS.open("/dev.json", "r"); + if (!f) return F("{}"); + String s = f.readString(); + f.close(); + return s; +} diff --git a/usermods/dpx_matrix/dpx_tc.h b/usermods/dpx_matrix/dpx_tc.h new file mode 100644 index 0000000000..ce843b444f --- /dev/null +++ b/usermods/dpx_matrix/dpx_tc.h @@ -0,0 +1,111 @@ +// ================================================================================ +// dpx_tc.h — Timecode Display Helper +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// Ported/adapted from dpx_tc001 ServerManager.cpp::pushTCDisplay() +// (original work, not AWTRIX-derived) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_tc.h +// Purpose: Parses HH:MM:SS:FF timecode strings, renders them on the matrix, +// and manages the TC display lock (auto-switches to tc app, disables +// auto-transition, auto-restores after DPX_TC_DWELL_MS). +// +// Mode A (DPX_TC_SHOW_FRAMES=false, default): +// Renders HH:MM:SS as text. Bottom 2 rows (6-7) show a frame-progress bar +// that fills left-to-right green→amber as frames advance within the second. +// +// Mode B (DPX_TC_SHOW_FRAMES=true): +// Renders compact MM:SS.FF — fits 32px wide, no bar. +// +// ================================================================================ + +#pragma once +#include "dpx_apps.h" + +static unsigned long dpxTcLastMs = 0; // millis() of last TC packet +static bool dpxTcLocked = false; // display locked to TC app + +// Parse "HH:MM:SS:FF" or "HH:MM:SS,FF" into components. +// Returns false if parse failed. +static bool dpxParseTc(const String& tc, int& h, int& m, int& s, int& f) { + h = m = s = f = 0; + return sscanf(tc.c_str(), "%d:%d:%d%*c%d", &h, &m, &s, &f) >= 3; +} + +// Push a timecode packet — builds a custom app JSON and sets "tc" app. +static void dpxPushTC(const String& tc, int fps = 30) { + int h, m, s, f; + if (!dpxParseTc(tc, h, m, s, f)) return; + if (f >= fps) f = fps - 1; + + DpxCustomApp app; + app.valid = true; + app.noScroll = true; + app.color = 0xFFFFFF; + app.topText = true; + + if (DPX_TC_SHOW_FRAMES) { + // Mode B: MM:SS.FF + char buf[12]; + snprintf(buf, sizeof(buf), "%02d:%02d.%02d", m, s, f); + app.text = buf; + } else { + // Mode A: HH:MM:SS + frame progress bar + char buf[12]; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", h, m, s); + app.text = buf; + + // Build progress bar as draw commands + int barW = (f * DPX_MATRIX_W) / fps; + // Background bar — rows 6-7 + DpxDrawCmd bg; + bg.cmd = "df"; bg.n[0]=0; bg.n[1]=6; bg.n[2]=DPX_MATRIX_W; bg.n[3]=2; bg.color=0x1a1a1a; + app.drawCmds.push_back(bg); + // Progress fill — green→amber + if (barW > 0) { + DpxDrawCmd bar; + bar.cmd = "df"; bar.n[0]=0; bar.n[1]=6; bar.n[2]=barW; bar.n[3]=2; + uint8_t r = (uint8_t)((barW * 255) / DPX_MATRIX_W); + uint8_t g = (uint8_t)(200 - (barW * 100) / DPX_MATRIX_W); + bar.color = ((uint32_t)r << 16) | ((uint32_t)g << 8); + app.drawCmds.push_back(bar); + } + } + + // Install as custom app "tc" + dpxCustom["tc"] = app; + dpxRebuildLoop(); + + // Lock display to tc app + dpxTcLastMs = millis(); + if (!dpxTcLocked) { + // Switch to tc app and disable auto-transition + for (int i = 0; i < (int)dpxApps.size(); i++) { + if (dpxApps[i].name == "tc") { + dpxCurrentApp = i; + dpxAppStartMs = millis(); + dpxScroll.stop(); + break; + } + } + dpxAutoTrans = false; + dpxTcLocked = true; + } +} + +// TC dwell tick — call from loop(). Restores auto-transition after dwell. +static void dpxTcDwellTick() { + if (!dpxTcLocked) return; + if (DPX_TC_HOLD) return; // never auto-dismiss in hold mode + if (millis() - dpxTcLastMs > DPX_TC_DWELL_MS) { + // Remove tc app and restore auto-transition + dpxCustom.erase("tc"); + dpxRebuildLoop(); + dpxAutoTrans = true; + dpxTcLocked = false; + dpxNextApp(); + } +} diff --git a/usermods/dpx_matrix/dpx_text.h b/usermods/dpx_matrix/dpx_text.h new file mode 100644 index 0000000000..21c3b38468 --- /dev/null +++ b/usermods/dpx_matrix/dpx_text.h @@ -0,0 +1,174 @@ +// ================================================================================ +// dpx_text.h — Text Rendering for 32×8 LED Matrix +// ================================================================================ +// Original work — dubpixel / dpx_tc002 (MIT) +// ================================================================================ +// PROJECT: dpx_tc002_frm +// ================================================================================ +// +// File: dpx_text.h +// Purpose: Pixel-level text rendering using dpx_font.h onto WLED's LED buffer. +// Functions operate on a 32-pixel-wide, 8-pixel-tall matrix. +// Pixel (x, y) = strip index y*32 + x. +// Caller must hold the strip lock / call from handleOverlayDraw(). +// +// ================================================================================ + +#pragma once +#include "dpx_font.h" + +// Matrix dimensions — Ulanzi TC001 +static const int DPX_MATRIX_W = 32; +static const int DPX_MATRIX_H = 8; + +// ── Raw pixel write ──────────────────────────────────────────────────────────── +// Writes one pixel to the WLED LED strip buffer. +// Clamps silently on out-of-bounds coordinates. +static inline void dpxSetPixel(int x, int y, uint32_t color) { + if (x < 0 || x >= DPX_MATRIX_W || y < 0 || y >= DPX_MATRIX_H) return; + strip.setPixelColor(y * DPX_MATRIX_W + x, color); +} + +static inline uint32_t dpxGetPixel(int x, int y) { + if (x < 0 || x >= DPX_MATRIX_W || y < 0 || y >= DPX_MATRIX_H) return 0; + return strip.getPixelColor(y * DPX_MATRIX_W + x); +} + +// ── Clear a rectangular region ──────────────────────────────────────────────── +static inline void dpxFillRect(int x, int y, int w, int h, uint32_t color) { + for (int row = y; row < y + h; row++) + for (int col = x; col < x + w; col++) + dpxSetPixel(col, row, color); +} + +// Clear entire matrix to black. +static inline void dpxClear() { + dpxFillRect(0, 0, DPX_MATRIX_W, DPX_MATRIX_H, 0x000000); +} + +// ── Rainbow colour for a character index ────────────────────────────────────── +static inline uint32_t dpxRainbowColor(int charIdx, int totalChars) { + // Evenly distribute hue across the string. + // WLED's CRGBW(CHSV) constructor applies the rainbow-method conversion. + uint8_t hue = (totalChars > 1) + ? (uint8_t)((uint32_t)charIdx * 255 / totalChars) + : 0; + CRGBW rgb = CHSV(hue, 255, 255); + return (uint32_t)rgb.r << 16 | (uint32_t)rgb.g << 8 | rgb.b; +} + +// ── Draw a single glyph at (x, y) ───────────────────────────────────────────── +// x, y = top-left corner. Returns the x position after the character (x + DPX_FONT_W + gap). +// Clips to matrix bounds. Columns with x < 0 are skipped (off-left). +static int dpxDrawChar(int x, int y, char c, uint32_t color) { + const uint8_t* glyph = dpxFontGlyph(c); + for (int col = 0; col < DPX_FONT_W; col++) { + int px = x + col; + if (px < 0) continue; + if (px >= DPX_MATRIX_W) break; + uint8_t colData = pgm_read_byte(glyph + col); + for (int row = 0; row < DPX_FONT_H; row++) { + int py = y + row; + if (colData & (1 << row)) { + dpxSetPixel(px, py, color); + } + } + } + return x + DPX_FONT_W + DPX_FONT_GAP; +} + +// ── Render a text string at (x, y) ──────────────────────────────────────────── +// Renders left to right from (x, y). Clips at matrix edges. +// rainbow=true overrides color with per-character rainbow. +// Returns the x position after the last character. +static int dpxRenderText(int x, int y, const char* text, uint32_t color, bool rainbow = false) { + if (!text) return x; + int n = strlen(text); + int curX = x; + for (int i = 0; i < n; i++) { + uint32_t c = rainbow ? dpxRainbowColor(i, n) : color; + curX = dpxDrawChar(curX, y, text[i], c); + if (curX >= DPX_MATRIX_W) break; // off-right edge + } + return curX; +} + +// ── Scroll state (one active scroll per display) ─────────────────────────────── +struct DpxScrollState { + String text; + uint32_t color = 0xFFFFFF; + bool rainbow = false; + int y = 0; // row (0 = top) + int scrollX = DPX_MATRIX_W; // current x offset (starts at right edge) + int speedMs = 50; // ms between scroll steps (lower = faster) + unsigned long lastStepMs = 0; + bool active = false; + int16_t repeat = -1; // scroll repeat count (-1 = infinite) + int16_t repeatsDone = 0; + int textWidth = 0; // cached pixel width + + void start(const String& t, uint32_t col, bool rb, int y_, int speedPct, int16_t rep) { + text = t; + color = col; + rainbow = rb; + y = y_; + speedMs = max(10, (int)(50 * 100 / max(1, speedPct))); + repeat = rep; + repeatsDone = 0; + textWidth = dpxTextPixelWidth(t.c_str()); + scrollX = DPX_MATRIX_W; + lastStepMs = 0; + active = true; + } + + void stop() { active = false; } + + // Returns true when the current scroll cycle is complete (scrolled off left). + // Caller should call again to advance another repeat or stop. + bool tick() { + if (!active) return false; + unsigned long now = millis(); + if (now - lastStepMs < (unsigned long)speedMs) return false; + lastStepMs = now; + scrollX--; + // Complete when text has fully scrolled off left + if (scrollX < -(textWidth)) { + repeatsDone++; + if (repeat >= 0 && repeatsDone >= repeat) { + active = false; + return true; // done + } + scrollX = DPX_MATRIX_W; // wrap + } + return false; // still running + } + + // Render current scroll position. Call after tick(). + void render() const { + if (!active) return; + dpxRenderText(scrollX, y, text.c_str(), color, rainbow); + } +}; + +// ── Draw a horizontal line (e.g., progress bar) ─────────────────────────────── +static inline void dpxDrawHLine(int x, int y, int w, uint32_t color) { + for (int i = 0; i < w; i++) dpxSetPixel(x + i, y, color); +} + +// ── Draw a filled rectangle outline ────────────────────────────────────────── +static inline void dpxDrawRect(int x, int y, int w, int h, uint32_t color) { + for (int i = 0; i < w; i++) { dpxSetPixel(x+i, y, color); dpxSetPixel(x+i, y+h-1, color); } + for (int i = 1; i < h-1; i++) { dpxSetPixel(x, y+i, color); dpxSetPixel(x+w-1, y+i, color); } +} + +// ── Progress bar: rows 6-7, full width 32px ─────────────────────────────────── +// pct 0-100, barColor = fill, bgColor = background +static void dpxDrawProgressBar(int pct, uint32_t barColor, uint32_t bgColor) { + int filled = (pct * DPX_MATRIX_W) / 100; + filled = constrain(filled, 0, DPX_MATRIX_W); + for (int x = 0; x < DPX_MATRIX_W; x++) { + uint32_t c = (x < filled) ? barColor : bgColor; + dpxSetPixel(x, 6, c); + dpxSetPixel(x, 7, c); + } +} diff --git a/usermods/dpx_matrix/library.json b/usermods/dpx_matrix/library.json new file mode 100644 index 0000000000..bd07292368 --- /dev/null +++ b/usermods/dpx_matrix/library.json @@ -0,0 +1,5 @@ +{ + "name": "dpx_matrix", + "build": { "libArchive": false }, + "dependencies": {} +} diff --git a/wled00/const.h b/wled00/const.h index 04ff8ded61..3b435d1b5b 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -230,6 +230,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h" #define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h" #define USERMOD_ID_USER_FX 58 //Usermod "user_fx" +#define USERMOD_ID_DPX_MATRIX 59 //Usermod "dpx_matrix" — dubpixel TC002 LED matrix display //Wifi encryption type #ifdef WLED_ENABLE_WPA_ENTERPRISE From 50c377cb398ea4908d1de4b2ac284372ed32bbff Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 18 Jul 2026 12:03:37 -0400 Subject: [PATCH 3/9] fix: web UI stability, firstboot config, AwtrixFont, serial IP, docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove custom /api/* routes — stripped dpx_api.h to /dpx status endpoint - Add dpx_mqtt.h: MQTT subscribe via WLED broker (dpx/# topics) - Add dpx_overlay.h: text overlay + pixel effects (sparkle/strobe/rain/twinkle/blink) - Add dpx_firstboot.h: write /cfg.json on first boot (dpx-tc002 AP, behav=1, 2D 32x8) - Replace 5x7 column-major font with AwtrixFont (BSD-3-Clause TomThumb-derived) - Rewrite dpx_text.h renderer for GFX row-major format; fix baseline (y=0 was off-screen) - Fix REGISTER_USERMOD missing from dpx_matrix.cpp — usermod now actually loads - Fix UDP crash: move dpxOscBegin() to connected() (lwip not ready in setup) - Rate-limit loop() to 50Hz — was hammering UDP socket stack on every tick - Fix root / route shadowing WLED web UI (ESPAsyncWebServer LIFO order) - Print IP to serial on WiFi connect; reprint when monitor opens - Guard DEFAULT_LED_COUNT in const.h to avoid redefinition warning - Refactor firstboot from raw JSON string to ArduinoJson builder - readme: filled in About, Getting Started, First Boot Defaults, Usage, Acknowledgments - platformio_override.ini: OTA env, shared common section, DPX_BTN pins --- dpx_tc002_frm.code-workspace | 3 +- platformio_override.ini | 68 +-- readme.md | 231 +++++---- usermods/dpx_matrix/dpx_api.h | 700 ++++++++++++++++------------ usermods/dpx_matrix/dpx_apps.h | 7 +- usermods/dpx_matrix/dpx_firstboot.h | 169 +++---- usermods/dpx_matrix/dpx_font.h | 652 +++++++++++++++++++++----- usermods/dpx_matrix/dpx_matrix.cpp | 8 + usermods/dpx_matrix/dpx_matrix.h | 227 ++++++++- usermods/dpx_matrix/dpx_persist.h | 12 + usermods/dpx_matrix/dpx_text.h | 66 ++- wled00/const.h | 4 +- 12 files changed, 1462 insertions(+), 685 deletions(-) diff --git a/dpx_tc002_frm.code-workspace b/dpx_tc002_frm.code-workspace index f23805033f..f5b8daea67 100644 --- a/dpx_tc002_frm.code-workspace +++ b/dpx_tc002_frm.code-workspace @@ -18,6 +18,7 @@ "**/dpx_reference/**": true, "**/WLED/**": true, "**/dpx_showsite_ops/**": true - } + }, + "platformio-ide.activeProjectPioEnv": "ulanzi_tc001" } } \ No newline at end of file diff --git a/platformio_override.ini b/platformio_override.ini index 7f2c899650..bc36e61793 100644 --- a/platformio_override.ini +++ b/platformio_override.ini @@ -7,59 +7,63 @@ ; LDR: GPIO35 I²C: GPIO21/22 Buttons: GPIO26/27/14 ; ; Usage: -; pio run -e ulanzi_tc001 # build only -; pio run -e ulanzi_tc001 -t upload # build + flash -; -; First time: -; npm ci && npm run build # generate html_*.h headers -; pio run -e ulanzi_tc001 +; pio run -e ulanzi_tc001 # build + flash via USB +; pio run -e ulanzi_tc001_ota # build + flash via WiFi OTA ; ================================================================================ -[env:ulanzi_tc001] -extends = env:esp32dev - -; ── Hardware ────────────────────────────────────────────────────────────────── +; ── Shared hardware + build flags ───────────────────────────────────────────── +[dpx_tc001_common] board = esp32dev board_build.mcu = esp32 board_build.f_cpu = 240000000L -upload_speed = 460800 - -; ── Custom usermod ──────────────────────────────────────────────────────────── -custom_usermods = dpx_matrix - -; ── Compile-time flags ──────────────────────────────────────────────────────── +custom_usermods = dpx_matrix build_flags = ${env:esp32dev.build_flags} - - ; ── Disable unused WLED features to save flash ────────────────────────── -D WLED_DISABLE_ALEXA -D WLED_DISABLE_LOXONE -D WLED_DISABLE_INFRARED -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_ADALIGHT -D WLED_DISABLE_ESPNOW - - ; ── Ulanzi TC001 hardware pin defaults ───────────────────────────────── - ; These are compile-time defaults. The user can override via WLED web UI. -D LEDPIN=32 + -D DEFAULT_LED_COUNT=256 -D BTNPIN=26 -D RLYPIN=-1 -D IRPIN=-1 -D STATUSPIN=-1 - - ; ── LittleFS instead of SPIFFS ───────────────────────────────────────── + -D DPX_BTN_LEFT=26 + -D DPX_BTN_MID=14 + -D DPX_BTN_RIGHT=27 -D WLED_USE_LITTLEFS - - ; ── Product identification ───────────────────────────────────────────── -D WLED_VERSION='"dpx_tc002-dev"' -D WLED_PRODUCT_NAME='"dpx_tc002"' -D WLED_INSTANCE_NAME='"dpx_tc002"' - -; ── Custom partition table (1.75MB app + 256KB LittleFS) ───────────────────── -; board_build.partitions = tools/TC001_partitions.csv -; Uncomment the line above once the custom partition table is added. -; For now, uses esp32dev default (1.25MB app). - -; ── Monitor ─────────────────────────────────────────────────────────────────── monitor_speed = 115200 monitor_filters = esp32_exception_decoder + +; ── USB flash ───────────────────────────────────────────────────────────────── +[env:ulanzi_tc001] +extends = env:esp32dev +board = ${dpx_tc001_common.board} +board_build.mcu = ${dpx_tc001_common.board_build.mcu} +board_build.f_cpu = ${dpx_tc001_common.board_build.f_cpu} +custom_usermods = ${dpx_tc001_common.custom_usermods} +build_flags = ${dpx_tc001_common.build_flags} +monitor_speed = ${dpx_tc001_common.monitor_speed} +monitor_filters = ${dpx_tc001_common.monitor_filters} +upload_speed = 460800 + +; ── OTA / WiFi flash ────────────────────────────────────────────────────────── +; OTA password: WLED → Config → Security & Updates (leave blank if unset) +[env:ulanzi_tc001_ota] +extends = env:esp32dev +board = ${dpx_tc001_common.board} +board_build.mcu = ${dpx_tc001_common.board_build.mcu} +board_build.f_cpu = ${dpx_tc001_common.board_build.f_cpu} +custom_usermods = ${dpx_tc001_common.custom_usermods} +build_flags = ${dpx_tc001_common.build_flags} +monitor_speed = ${dpx_tc001_common.monitor_speed} +monitor_filters = ${dpx_tc001_common.monitor_filters} +upload_protocol = espota +upload_port = 10.10.11.200 +; upload_flags = --auth=wledota diff --git a/readme.md b/readme.md index 84c7605004..eb055afd75 100644 --- a/readme.md +++ b/readme.md @@ -60,21 +60,10 @@

Table of Contents

    -
  1. - About The Project - -
  2. -
  3. - Getting Started - -
  4. -
  5. Usage
  6. -
  7. Reflection
  8. +
  9. About The Project
  10. +
  11. Getting Started
  12. +
  13. First Boot Defaults
  14. +
  15. Usage
  16. Roadmap
  17. Contributing
  18. License
  19. @@ -85,84 +74,155 @@

    About The Project

    -a lengthy description about the project that should probably be many lines. this is where you can get deep about shit and be like oh man its the best hot dog in the univberse because i use the koskusko mustart! -
    -*author(s): // www.dubpixel.tv - i@dubpixel.tv | other authors* -
    -

    Images

    +**dpx_tc002_frm** is a custom WLED firmware build for the [Ulanzi TC001](https://www.ulanzi.com/products/ulanzi-pixel-smart-clock-2882) pixel clock — a battery-powered ESP32 device with a 32×8 WS2812B LED matrix. It replaces the stock Awtrix firmware with a WLED base plus the `dpx_matrix` usermod, adding timecode display, OSC/MQTT control, scrolling text apps, pixel overlay effects, and first-boot hardware configuration. + +Built on top of [WLED](https://github.com/wled/WLED) (EUPL v1.2) — all WLED features remain fully functional. + +### What WLED brings + +- **200+ built-in LED effects** including 2D/matrix effects, audio-reactive, and palettes +- **Segments** — independent effects/colors on parts of the strip simultaneously +- **Up to 250 presets** with playlist support +- **JSON + HTTP APIs**, MQTT with Home Assistant discovery, E1.31/Art-Net/DDP +- **Multi-WiFi** with automatic AP fallback, OTA firmware updates +- **NTP time sync** with full timezone + DST support +- Full [WLED documentation at kno.wled.ge](https://kno.wled.ge) +- [WLED mobile app](https://kno.wled.ge/basics/getting-started/) for Android and iOS + +### What dpx_matrix adds + +- Scrolling/static **text app loop** (Time, Date, custom apps) with AwtrixFont +- **Timecode display** (LTC via OSC) with frame progress bar +- **Notifications** — one-shot priority messages +- **Text overlay** + pixel effects (sparkle, strobe, rain, twinkle, blink) on top of any WLED effect +- **OSC receiver** (UDP 4210) — compatible with dpx_tc001 and AWTRIX OSC senders +- **MQTT** via WLED's broker connection +- **First-boot config** — device is usable out of the box, no wizard required + +*author: [Joshua Fleitell](https://www.dubpixel.tv) — i@dubpixel.tv* + +> ⚠️ If you are prone to photosensitive epilepsy, avoid strobe/lightning effects and high speed settings. + +### Images ### FRONT ![FRONT][product-front] -### REAR +### REAR ![REAR][product-rear] ### FRONT Rendering ![FRONT][product-front-rendering] ### REAR Rendering ![REAR][product-rear-rendering] -### iBOM PCB Front -![iBOM Front][product-pcbFront] -### iBOM PCB Rear -![iBOM Front][product-pcbRear]

    (back to top)

    -### Built With - - * [![KiCad][KiCad.org]][KiCad-url] - * [![Fusion360][Fusion-360]][Autodesk-url] - * [![FastLed][FastLed.io]][FastLed-url] +### Built With - +* [![WLED][WLED-badge]][WLED-url] +* [![PlatformIO][PlatformIO-badge]][PlatformIO-url] +* [![ESP32][ESP32-badge]][ESP32-url]

    (back to top)

    ## Getting Started ### Prerequisites - * + * PlatformIO (VS Code extension or CLI) + * Node.js 20+ (`npm ci` before first build) + ### Installation - 1. + 1. Clone the repo and open in VS Code + 2. `npm ci && npm run build` — generate web UI headers + 3. Hit **Upload** (PlatformIO sidebar → `ulanzi_tc001`) or run `pio run -t upload -e ulanzi_tc001` + 4. On first boot the device writes its own config — see [First Boot Defaults](#first-boot-defaults) below + +

    (back to top)

    + + +## First Boot Defaults + +When you flash this firmware the device is **not stock WLED** — it boots into a pre-configured state. Here's what to expect: + +### Connecting for the first time + +1. Power the device +2. Look for WiFi network **`dpx-tc002`** (not `WLED-AP`) +3. Password: **`dubpixel1`** (not `wled1234`) +4. Connect and go to **`http://4.3.2.1`** in a browser +5. Set your WiFi network under **WiFi Setup** +6. The device joins your network and is accessible at **`http://dpx-tc002.local`** + +> This AP stays open indefinitely whenever the device is not connected to WiFi — no 5-minute timeout. + +### Default hardware config (written once on first boot) + +| Setting | Value | Notes | +|---|---|---| +| **AP SSID** | `dpx-tc002` | | +| **AP Password** | `dubpixel1` | | +| **mDNS** | `dpx-tc002.local` | | +| **LED GPIO** | 32 | | +| **LED Count** | 256 | 32×8 matrix | +| **LED Type** | WS2812B GRB | | +| **2D Panel** | 32×8, non-serpentine | Toggle serpentine in WLED → LED Preferences | +| **Buttons** | GPIO 26 / 14 / 27 | Configurable macros in WLED | +| **Transitions** | 0 ms | Instant — better for text | +| **WiFi** | Not saved | Configure on first connect | + +> Reflashing **preserves** your saved WiFi credentials. To reset to factory defaults, delete `/cfg.json` via WLED → File Manager, then reboot. + +### Control interfaces + +| Interface | How | +|---|---| +| **Web UI** | `http://dpx-tc002.local` | +| **OSC** | UDP 4210 — `/dpx/notify`, `/dpx/tc`, `/dpx/app/`, `/dpx/overlay`, `/dpx/effect` | +| **MQTT** | `{deviceTopic}/dpx/#` — same structure as OSC | +| **JSON** | `POST /json {"dpx":{...}}` — WLED standard JSON API | +| **Serial** | 115200 baud — prints IP on connect |

    (back to top)

    ## Usage -1. - -## Reflection +Set a custom scrolling app via MQTT: +``` +{deviceTopic}/dpx/app/mylabel {"text":"LIVE","color":"#FF4400","duration":10} +``` -* what did we learn? - - _x_ -* what do we like/hate? - - _y_ -* what would/could we do differently? - - _z_ - +Via WLED JSON API: +```json +POST /json +{"dpx": {"notify": {"text": "HELLO", "color": "#FF0000"}}} +``` + +See [First Boot Defaults](#first-boot-defaults) for all control interfaces. + +

    (back to top)

    + + ## Roadmap -- [ ] Feature 1 - - [ ] Nested Feature +- [ ] Button macros (prev/next app, dismiss notification, show IP) +- [ ] LDR-based auto brightness +- [ ] Temperature/humidity sensor display (I²C) +- [ ] Preset integration — trigger dpx apps from WLED presets +- [ ] 2D effect groups in web UI -See the [open issues](https://github.com/dubpixel/dpx_tc002_frm/issues) for a full list of proposed features (and known issues). +See the [open issues](https://github.com/dubpixel/dpx_tc002_frm/issues) for a full list of proposed features and known issues. ## Contributing @@ -185,62 +245,47 @@ Don't forget to give the project a star! Thanks again! ## License -Distributed under the [LICENSE_TYPE] License. See `LICENSE.txt` for more information. +This firmware is distributed under the **EUPL v1.2** (inherited from WLED). See `LICENSE` for details. + +The `dpx_matrix` usermod (original work) is additionally available under MIT. + +AwtrixFont used in dpx_font.h is BSD 3-Clause — see header for full attribution. ## Contact - ### Joshua Fleitell - i@dubpixel.tv + ### Joshua Fleitell — i@dubpixel.tv Project Link: [https://github.com/dubpixel/dpx_tc002_frm](https://github.com/dubpixel/dpx_tc002_frm) ## Acknowledgments - +* [WLED](https://github.com/wled/WLED) — the firmware base. Originally by [Aircoookie](https://github.com/Aircoookie), now community-maintained. EUPL v1.2. +* [AwtrixFont](https://github.com/Blueforcer/awtrix3) — TomThumb-derived 3×5 pixel font by Blueforcer et al. BSD 3-Clause. +* [Ulanzi TC001](https://www.ulanzi.com/products/ulanzi-pixel-smart-clock-2882) — the hardware platform.

    (back to top)

    - [contributors-shield]: https://img.shields.io/github/contributors/dubpixel/dpx_tc002_frm.svg?style=flat-square [contributors-url]: https://github.com/dubpixel/dpx_tc002_frm/graphs/contributors -[forks-shield]: https://img.shields.io/github/forks/gdubpixel/dpx_tc002_frm.svg?style=flat-square +[forks-shield]: https://img.shields.io/github/forks/dubpixel/dpx_tc002_frm.svg?style=flat-square [forks-url]: https://github.com/dubpixel/dpx_tc002_frm/network/members [stars-shield]: https://img.shields.io/github/stars/dubpixel/dpx_tc002_frm.svg?style=flat-square [stars-url]: https://github.com/dubpixel/dpx_tc002_frm/stargazers [issues-shield]: https://img.shields.io/github/issues/dubpixel/dpx_tc002_frm.svg?style=flat-square [issues-url]: https://github.com/dubpixel/dpx_tc002_frm/issues [license-shield]: https://img.shields.io/github/license/dubpixel/dpx_tc002_frm.svg?style=flat-square -[license-url]: https://github.com/dubpixel/dpx_tc002_frm/blob/main/LICENSE.txt +[license-url]: https://github.com/dubpixel/dpx_tc002_frm/blob/main/LICENSE [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555 [linkedin-url]: https://linkedin.com/in/jfleitell [product-front]: images/front.png [product-rear]: images/rear.png [product-front-rendering]: images/front_render.png [product-rear-rendering]: images/rear_render.png -[product-pcbFront]: images/pcb_front.png -[product-pcbRear]: images/pcb_rear.png -[Next.js]: https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white -[Next-url]: https://nextjs.org/ -[React.js]: https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB -[React-url]: https://reactjs.org/ -[Vue.js]: https://img.shields.io/badge/Vue.js-35495E?style=for-the-badge&logo=vuedotjs&logoColor=4FC08D -[Vue-url]: https://vuejs.org/ -[Angular.io]: https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular&logoColor=white -[Angular-url]: https://angular.io/ -[Svelte.dev]: https://img.shields.io/badge/Svelte-4A4A55?style=for-the-badge&logo=svelte&logoColor=FF3E00 -[Svelte-url]: https://svelte.dev/ -[Laravel.com]: https://img.shields.io/badge/Laravel-FF2D20?style=for-the-badge&logo=laravel&logoColor=white -[Laravel-url]: https://laravel.com -[Bootstrap.com]: https://img.shields.io/badge/Bootstrap-563D7C?style=for-the-badge&logo=bootstrap&logoColor=white -[Bootstrap-url]: https://getbootstrap.com -[JQuery.com]: https://img.shields.io/badge/jQuery-0769AD?style=for-the-badge&logo=jquery&logoColor=white -[JQuery-url]: https://jquery.com -[KiCad.org]: https://img.shields.io/badge/KiCad-v8.0.6-blue -[KiCad-url]: https://kicad.org -[Fusion-360]: https://img.shields.io/badge/Fusion360-v4.2.0-green -[Autodesk-url]: https://autodesk.com -[FastLed.io]: https://img.shields.io/badge/FastLED-v3.9.9-red -[FastLed-url]: https://fastled.io +[WLED-badge]: https://img.shields.io/badge/WLED-17.0.0--dev-blue?style=flat-square +[WLED-url]: https://github.com/wled/WLED +[PlatformIO-badge]: https://img.shields.io/badge/PlatformIO-ESP32-orange?style=flat-square +[PlatformIO-url]: https://platformio.org +[ESP32-badge]: https://img.shields.io/badge/ESP32--WROOM--32D-240MHz-green?style=flat-square +[ESP32-url]: https://www.espressif.com/en/products/socs/esp32 diff --git a/usermods/dpx_matrix/dpx_api.h b/usermods/dpx_matrix/dpx_api.h index 1ab3d2c575..8ccc1d07a7 100644 --- a/usermods/dpx_matrix/dpx_api.h +++ b/usermods/dpx_matrix/dpx_api.h @@ -1,386 +1,472 @@ // ================================================================================ -// dpx_api.h — HTTP Route Registration (AsyncWebServer) +// dpx_api.h — HTTP Routes: pages + REST API // ================================================================================ // Original work — dubpixel / dpx_tc002 (MIT) -// Behavioral reference: SPEC.md §5 (HTTP API Reference) -// Implementation adapted from dpx_tc001 ServerManager.cpp (original work) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ // // File: dpx_api.h -// Purpose: Register all custom HTTP routes with WLED's AsyncWebServer instance. -// Call dpxRegisterRoutes() once from DpxMatrix::setup(). +// Purpose: Register all HTTP routes for the dpx_matrix usermod. // -// Routes registered: -// GET /ctrl, /browse, /api-ref, /screen, /fullscreen -// GET /api/loop, /api/apps, /api/custom, /api/settings, /api/time, -// /api/dev, /api/stats, /api/screen, /api/effects, /api/transitions, -// /api/osc/listeners, /api/reboot -// POST /api/notify, /api/notify/dismiss, /api/custom, /api/switch, -// /api/nextapp, /api/previousapp, /api/power, /api/settings, -// /api/moodlight, /api/indicator1/2/3, /api/rtttl, /api/sound, -// /api/apps, /api/reorder, /api/time, /api/syncntp, /api/rename, -// /api/tc, /api/dev, /api/osc/listeners -// DELETE /api/osc/listeners +// Pages: +// GET /ctrl → Control panel (dpx_html.h → ctrl_html) +// GET /browse → Icon browser (dpx_html.h → browse_html) +// GET /api-ref → API reference (dpx_html.h → apiref_html) +// GET /screen → Live matrix view (dpx_html.h → screenfull_html) +// +// API: +// GET/POST /api/stats device stats +// GET /api/apps app list +// GET /api/loop app loop map +// POST /api/notify push notification +// POST /api/notify/dismiss dismiss held notification +// GET/POST /api/custom get or push custom app (?name=) +// POST /api/switch switch to named app +// POST /api/nextapp advance loop +// POST /api/previousapp go back in loop +// POST /api/power {"power":true/false} +// POST /api/indicator1|2|3 {"color":[r,g,b],"blink":ms} +// GET/POST /api/time get/set device time +// POST /api/syncntp re-trigger NTP sync +// GET/POST /api/settings DPX + WLED settings +// GET/POST /api/dev raw dev.json +// GET/POST/DELETE /api/osc/listeners OSC listener registry +// POST /api/moodlight enable WLED effects (disable matrix overlay) +// POST /api/rtttl play RTTTL melody on TC001 piezo buzzer (GPIO 15) +// POST /api/sound stub +// POST /api/rename LittleFS rename +// GET /api/effects WLED effect names +// GET /api/transitions empty list (not implemented) +// GET/POST /api/reboot restart device +// GET /dpx legacy status (compat) +// GET /dpx/screen legacy pixel dump (compat) // // ================================================================================ #pragma once -#include -#include #include "dpx_html.h" -#include "dpx_osc.h" -#include "dpx_tc.h" -// Indicator pixel colors (rendered in handleOverlayDraw) -uint32_t dpxIndicator[3] = {0, 0, 0}; +// dpxIndicator is declared extern in dpx_osc.h; defined in dpx_matrix.cpp. +extern uint32_t dpxIndicator[3]; + +// ── Helpers ─────────────────────────────────────────────────────────────────── -// Helper: get plain text body as String +// Get plain-text POST body from AsyncWebServerRequest. static inline String dpxBody(AsyncWebServerRequest* req) { - if (req->hasParam("plain", true)) { + if (req->hasParam("plain", true)) return req->getParam("plain", true)->value(); - } return ""; } -// Helper: read and return /api/screen — 256 RGB values as JSON array +// 256-pixel screen dump as JSON array. static String dpxScreenJson() { DynamicJsonDocument doc(4096); JsonArray arr = doc.to(); - for (int i = 0; i < 256; i++) { - uint32_t c = strip.getPixelColor(i); - // WLED returns WRGB — extract RGB - arr.add((uint32_t)(c & 0x00FFFFFF)); - } + for (int i = 0; i < 256; i++) + arr.add((uint32_t)(strip.getPixelColor(i) & 0x00FFFFFF)); String s; serializeJson(doc, s); return s; } -// Helper: basic stats JSON +// Device stats JSON (shared by /dpx and /api/stats). static String dpxStatsJson() { DynamicJsonDocument doc(512); - doc["version"] = "dpx_tc002"; - doc["uptime"] = millis() / 1000; - doc["ram"] = ESP.getFreeHeap(); - doc["ip"] = WiFi.localIP().toString(); - doc["rssi"] = WiFi.RSSI(); - doc["hostname"] = WiFi.getHostname(); + doc[F("version")] = F("dpx_tc002"); + doc[F("uptime")] = millis() / 1000; + doc[F("ram")] = ESP.getFreeHeap(); + doc[F("ip")] = WiFi.localIP().toString(); + doc[F("rssi")] = WiFi.RSSI(); + doc[F("hostname")] = WiFi.getHostname(); + doc[F("app")] = (dpxCurrentApp < (int)dpxApps.size()) + ? dpxApps[dpxCurrentApp].name : String(); + doc[F("notif")] = (int)dpxNotifQueue.size(); + doc[F("autoTrans")] = dpxAutoTrans; + doc[F("enabled")] = dpxEnabled; + String s; serializeJson(doc, s); return s; +} + +// Settings JSON: DPX runtime + WLED globals. +// GET /api/settings returns this; POST /api/settings applies supported keys. +static String dpxSettingsJson() { + DynamicJsonDocument doc(768); + doc[F("BRI")] = (int)bri; + doc[F("ATIME")] = DPX_ATIME; + doc[F("ATRANS")] = DPX_ATRANS; + doc[F("SSPEED")] = DPX_SSPEED; + doc[F("UPPERCASE")] = DPX_UPPERCASE; + doc[F("Timezone")] = DPX_TIMEZONE; + doc[F("MQTT_PREFIX")] = String(mqttDeviceTopic); String s; serializeJson(doc, s); return s; } +// Apply settings from JSON body to DPX runtime + WLED globals. +static void dpxApplySettings(const String& body) { + DynamicJsonDocument doc(512); + if (deserializeJson(doc, body)) return; + + if (doc.containsKey("BRI")) { + bri = (uint8_t)constrain(doc["BRI"].as(), 0, 255); + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + if (doc.containsKey("ATIME")) { DPX_ATIME = doc["ATIME"].as(); } + if (doc.containsKey("ATRANS")) { DPX_ATRANS = doc["ATRANS"].as(); dpxAutoTrans = DPX_ATRANS; } + if (doc.containsKey("SSPEED")) { DPX_SSPEED = doc["SSPEED"].as(); } + if (doc.containsKey("UPPERCASE")){ DPX_UPPERCASE = doc["UPPERCASE"].as(); } + // Timezone is handled via /api/syncntp for full resync + if (doc.containsKey("Timezone")) { + DPX_TIMEZONE = doc["Timezone"].as(); + setenv("TZ", DPX_TIMEZONE.c_str(), 1); + tzset(); + dpxMergeDev(("{\"timezone_posix\":\"" + DPX_TIMEZONE + "\"}").c_str()); + } +} + +// ── Route registration ──────────────────────────────────────────────────────── + static void dpxRegisterRoutes() { - // ── Web pages ────────────────────────────────────────────────────────── - server.on("/", HTTP_GET, [](AsyncWebServerRequest* r) { - r->redirect("/ctrl"); - }); - server.on("/ctrl", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send_P(200, "text/html", ctrl_html); + + // ── Pages ───────────────────────────────────────────────────────────────── + server.on("/ctrl", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send_P(200, PSTR("text/html"), ctrl_html); }); - server.on("/browse", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send_P(200, "text/html", browse_html); + server.on("/browse", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send_P(200, PSTR("text/html"), browse_html); }); server.on("/api-ref", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send_P(200, "text/html", apiref_html); + r->send_P(200, PSTR("text/html"), apiref_html); }); - server.on("/screen", HTTP_GET, [](AsyncWebServerRequest* r) { - // /screen uses screenfull_html but since it has %%FPS%% placeholder, - // serve it statically; JS fetches /api/screen. - r->send_P(200, "text/html", screenfull_html); - }); - server.on("/fullscreen", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send_P(200, "text/html", screenfull_html); + server.on("/screen", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send_P(200, PSTR("text/html"), screenfull_html); }); - // ── Read endpoints ──────────────────────────────────────────────────── - server.on("/api/loop", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, "application/json", dpxGetLoopJson()); - }); - server.on("/api/apps", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, "application/json", dpxGetAppsJson()); - }); - server.on("/api/custom", HTTP_GET, [](AsyncWebServerRequest* r) { - if (r->hasParam("name")) { - r->send(200, "application/json", - dpxGetCustomAppJson(r->getParam("name")->value())); - } else { - r->send(200, "application/json", dpxGetAppsJson()); - } - }); - server.on("/api/screen", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, "application/json", dpxScreenJson()); + // ── Stats ───────────────────────────────────────────────────────────────── + // Legacy endpoint kept for back-compat + server.on("/dpx", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, F("application/json"), dpxStatsJson()); }); server.on("/api/stats", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, "application/json", dpxStatsJson()); + r->send(200, F("application/json"), dpxStatsJson()); }); - server.on("/api/time", HTTP_GET, [](AsyncWebServerRequest* r) { - time_t now; struct tm ti; - time(&now); localtime_r(&now, &ti); - char buf[32]; strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &ti); - StaticJsonDocument<128> doc; - doc["local"] = buf; doc["utc"] = (long)now; - String j; serializeJson(doc, j); - r->send(200, "application/json", j); + + // ── Screen dump ─────────────────────────────────────────────────────────── + server.on("/dpx/screen", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, F("application/json"), dpxScreenJson()); }); - server.on("/api/dev", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, "application/json", dpxReadDevJson()); + server.on("/api/screen", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, F("application/json"), dpxScreenJson()); }); - server.on("/api/osc/listeners", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, "application/json", dpxOscListenersJson()); + + // ── App loop ────────────────────────────────────────────────────────────── + server.on("/api/apps", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, F("application/json"), dpxGetAppsJson()); }); - server.on("/api/reboot", HTTP_ANY, [](AsyncWebServerRequest* r) { - r->send(200, "text/plain", "OK"); - delay(200); - ESP.restart(); + server.on("/api/loop", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, F("application/json"), dpxGetLoopJson()); }); - // WLED's /api/effects and /api/transitions handled by WLED itself; add stubs - server.on("/api/effects", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, "application/json", F("[]")); + + // ── Notifications ───────────────────────────────────────────────────────── + server.on("/api/notify", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + if (body.length()) dpxPushNotification(body.c_str()); + r->send(200, F("application/json"), F("{\"ok\":true}")); }); - server.on("/api/transitions", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, "application/json", F("[\"None\",\"Fade\",\"Slide\"]")); + server.on("/api/notify/dismiss", HTTP_POST, [](AsyncWebServerRequest* r) { + dpxDismissNotification(); + r->send(200, F("application/json"), F("{\"ok\":true}")); }); - // ── Control endpoints ───────────────────────────────────────────────── - server.on("/api/notify", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - String body((char*)data, len); - dpxPushNotification(body.c_str()) - ? r->send(200, "text/plain", "OK") - : r->send(500, "text/plain", "ParseError"); - }); - - server.on("/api/notify/dismiss", HTTP_ANY, [](AsyncWebServerRequest* r) { - dpxDismissNotification(); - r->send(200, "text/plain", "OK"); + // ── Custom apps (GET=load, POST=push, name in query) ────────────────────── + server.on("/api/custom", HTTP_ANY, [](AsyncWebServerRequest* r) { + String name = r->hasParam("name") ? r->getParam("name")->value() : String(); + if (name.isEmpty()) { r->send(400, F("text/plain"), F("name required")); return; } + + if (r->method() == HTTP_GET) { + r->send(200, F("application/json"), dpxGetCustomAppJson(name)); + return; + } + // POST: push or delete (empty body = delete) + String body = dpxBody(r); + dpxSetCustomApp(name, body.c_str()); + r->send(200, F("application/json"), F("{\"ok\":true}")); }); - server.on("/api/custom", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - String name = r->hasParam("name") ? r->getParam("name")->value() : ""; - String body((char*)data, len); - body.trim(); - if (name.length()) dpxSetCustomApp(name, body.c_str()); - r->send(200, "text/plain", "OK"); - }); - - server.on("/api/switch", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - String body((char*)data, len); - dpxSwitchToApp(body.c_str()) - ? r->send(200, "text/plain", "OK") - : r->send(500, "text/plain", "FAILED"); - }); - - server.on("/api/nextapp", HTTP_ANY, [](AsyncWebServerRequest* r) { - dpxNextApp(); r->send(200, "text/plain", "OK"); + // ── App navigation ──────────────────────────────────────────────────────── + server.on("/api/switch", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + bool ok = body.length() ? dpxSwitchToApp(body.c_str()) : false; + r->send(ok ? 200 : 400, F("application/json"), ok ? F("{\"ok\":true}") : F("{\"error\":\"not found\"}")); + }); + server.on("/api/nextapp", HTTP_POST, [](AsyncWebServerRequest* r) { + dpxNextApp(); + r->send(200, F("application/json"), F("{\"ok\":true}")); }); - server.on("/api/previousapp", HTTP_ANY, [](AsyncWebServerRequest* r) { - dpxPrevApp(); r->send(200, "text/plain", "OK"); + server.on("/api/previousapp", HTTP_POST, [](AsyncWebServerRequest* r) { + dpxPrevApp(); + r->send(200, F("application/json"), F("{\"ok\":true}")); }); - server.on("/api/power", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - String body((char*)data, len); - StaticJsonDocument<64> doc; - if (!deserializeJson(doc, body) && doc.containsKey("power")) { - bool on = doc["power"].as(); - bri = on ? (briLast > 0 ? briLast : 128) : 0; - stateUpdated(CALL_MODE_DIRECT_CHANGE); - } - r->send(200, "text/plain", "OK"); - }); - - server.on("/api/tc", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - String body((char*)data, len); - body.trim(); body.replace("\"", ""); - if (body.length() >= 8) { - dpxPushTC(body); - r->send(200, "text/plain", "OK"); + // ── Power on/off ────────────────────────────────────────────────────────── + // {"power": true/false} — maps to WLED brightness + server.on("/api/power", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + DynamicJsonDocument doc(64); + if (!deserializeJson(doc, body) && doc.containsKey("power")) { + bool on = doc["power"].as(); + if (on) { + bri = briLast ? briLast : 128; } else { - r->send(400, "text/plain", "BadRequest"); + briLast = bri; + bri = 0; } - }); - - server.on("/api/dev", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - String body((char*)data, len); - dpxMergeDev(body.c_str()) - ? r->send(200, "text/plain", "OK") - : r->send(400, "text/plain", "BadRequest"); - }); - - server.on("/api/time", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - StaticJsonDocument<128> doc; - String body((char*)data, len); + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + r->send(200, F("application/json"), F("{\"ok\":true}")); + }); + + // ── Indicators ──────────────────────────────────────────────────────────── + // {"color":[r,g,b],"blink":ms} — blink is ignored (no HW PWM), color stored + auto handleIndicator = [](AsyncWebServerRequest* r, int idx) { + String body = dpxBody(r); + DynamicJsonDocument doc(128); + if (!deserializeJson(doc, body)) { + if (doc.containsKey("color")) { + JsonArray a = doc["color"].as(); + if (a.size() >= 3) + dpxIndicator[idx] = ((uint32_t)(uint8_t)a[0].as() << 16) + | ((uint32_t)(uint8_t)a[1].as() << 8) + | (uint32_t)(uint8_t)a[2].as(); + else + dpxIndicator[idx] = 0; + } + } + r->send(200, F("application/json"), F("{\"ok\":true}")); + }; + server.on("/api/indicator1", HTTP_POST, [handleIndicator](AsyncWebServerRequest* r){ handleIndicator(r, 0); }); + server.on("/api/indicator2", HTTP_POST, [handleIndicator](AsyncWebServerRequest* r){ handleIndicator(r, 1); }); + server.on("/api/indicator3", HTTP_POST, [handleIndicator](AsyncWebServerRequest* r){ handleIndicator(r, 2); }); + + // ── Time ────────────────────────────────────────────────────────────────── + server.on("/api/time", HTTP_ANY, [](AsyncWebServerRequest* r) { + if (r->method() == HTTP_POST) { + String body = dpxBody(r); + DynamicJsonDocument doc(64); if (!deserializeJson(doc, body) && doc.containsKey("utc")) { - time_t t = (time_t)doc["utc"].as(); - struct timeval tv = {t, 0}; + time_t t = (time_t)doc["utc"].as(); + struct timeval tv = { t, 0 }; settimeofday(&tv, nullptr); - r->send(200, "text/plain", "OK"); - } else { - r->send(400, "text/plain", "BadRequest"); - } - }); - - server.on("/api/syncntp", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - String body((char*)data, len); - if (body.length() > 2) { - StaticJsonDocument<256> doc; - if (!deserializeJson(doc, body)) { - if (doc.containsKey("timezone")) { - configTzTime(doc["timezone"].as(), "pool.ntp.org"); - } - } } - r->send(200, "text/plain", "OK"); - }); - - server.on("/api/rename", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - StaticJsonDocument<256> doc; - String body((char*)data, len); - if (deserializeJson(doc, body) || !doc.containsKey("from") || !doc.containsKey("to")) { - r->send(400, "text/plain", "BadRequest"); return; - } - String from = doc["from"].as(); - String to = doc["to"].as(); - if (!LittleFS.exists(from)) { r->send(404, "text/plain", "NotFound"); return; } - LittleFS.rename(from, to) - ? r->send(200, "text/plain", "OK") - : r->send(500, "text/plain", "Failed"); - }); - - server.on("/api/apps", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - // Reorder apps — array of name strings; rebuild loop in that order - DynamicJsonDocument doc(1024); - String body((char*)data, len); - if (deserializeJson(doc, body)) { r->send(400, "text/plain", "BadRequest"); return; } - // For now just acknowledge — reorder TODO - r->send(200, "text/plain", "OK"); - }); - - server.on("/api/reorder", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - r->send(200, "text/plain", "OK"); - }); - - // Indicator endpoints (1, 2, 3) - auto indicatorHandler = [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - // Extract indicator number from URL - String url = r->url(); - int num = url.charAt(url.length() - 1) - '0'; - if (num < 1 || num > 3) { r->send(400, "text/plain", "BadRequest"); return; } - StaticJsonDocument<256> doc; - String body((char*)data, len); - if (!deserializeJson(doc, body) && doc.containsKey("color")) { - JsonArray a = doc["color"].as(); - if (a.size() >= 3) { - uint32_t col = ((uint32_t)(uint8_t)a[0] << 16) - | ((uint32_t)(uint8_t)a[1] << 8) - | (uint32_t)(uint8_t)a[2]; - dpxIndicator[num - 1] = col; + r->send(200, F("application/json"), F("{\"ok\":true}")); + return; + } + // GET: return local time string + UTC epoch + time_t now; struct tm ti; + time(&now); localtime_r(&now, &ti); + char buf[24]; + strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &ti); + DynamicJsonDocument doc(128); + doc[F("local")] = buf; + doc[F("utc")] = (uint32_t)now; + String s; serializeJson(doc, s); + r->send(200, F("application/json"), s); + }); + + // ── NTP resync + timezone ───────────────────────────────────────────────── + // POST body (optional): {"timezone":"PST8PDT,...","server":"pool.ntp.org"} + server.on("/api/syncntp", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + DynamicJsonDocument doc(256); + if (!deserializeJson(doc, body)) { + if (doc.containsKey("timezone")) { + DPX_TIMEZONE = doc["timezone"].as(); + dpxMergeDev(("{\"timezone_posix\":\"" + DPX_TIMEZONE + "\"}").c_str()); } + } + // Apply TZ env variable + if (DPX_TIMEZONE.length()) { + setenv("TZ", DPX_TIMEZONE.c_str(), 1); + tzset(); + } + // Re-trigger ESP32 SNTP via configTzTime (sets TZ env + syncs) + String ntpSrv = (!doc.isNull() && doc.containsKey("server")) + ? doc["server"].as() : String(ntpServerName); + if (!ntpSrv.length()) ntpSrv = F("pool.ntp.org"); + + if (DPX_TIMEZONE.length()) { + configTzTime(DPX_TIMEZONE.c_str(), ntpSrv.c_str()); } else { - dpxIndicator[num - 1] = 0; + configTime(0, 0, ntpSrv.c_str()); } - r->send(200, "text/plain", "OK"); - }; - server.on("/api/indicator1", HTTP_POST, [](AsyncWebServerRequest* r){}, nullptr, indicatorHandler); - server.on("/api/indicator2", HTTP_POST, [](AsyncWebServerRequest* r){}, nullptr, indicatorHandler); - server.on("/api/indicator3", HTTP_POST, [](AsyncWebServerRequest* r){}, nullptr, indicatorHandler); - - // OSC listener add/delete - server.on("/api/osc/listeners", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - StaticJsonDocument<256> doc; - String body((char*)data, len); - if (deserializeJson(doc, body)) { r->send(400, "text/plain", "BadRequest"); return; } - String path = doc["path"].as(); - String channel = doc["channel"].as(); - String label = doc.containsKey("label") ? doc["label"].as() : channel; - if (!path.length() || !channel.length()) { r->send(400, "text/plain", "BadRequest"); return; } - // Update or add - bool found = false; - for (auto& lsr : dpxOscListeners) { - if (lsr.path == path) { lsr.channel = channel; lsr.label = label; found = true; break; } + r->send(200, F("application/json"), F("{\"ok\":true}")); + }); + + // ── Settings ────────────────────────────────────────────────────────────── + server.on("/api/settings", HTTP_ANY, [](AsyncWebServerRequest* r) { + if (r->method() == HTTP_POST) { + dpxApplySettings(dpxBody(r)); + r->send(200, F("application/json"), F("{\"ok\":true}")); + return; + } + r->send(200, F("application/json"), dpxSettingsJson()); + }); + + // ── dev.json (raw device settings) ──────────────────────────────────────── + server.on("/api/dev", HTTP_ANY, [](AsyncWebServerRequest* r) { + if (r->method() == HTTP_POST) { + String body = dpxBody(r); + if (body.length()) dpxMergeDev(body.c_str()); + r->send(200, F("application/json"), F("{\"ok\":true}")); + return; + } + r->send(200, F("application/json"), dpxReadDevJson()); + }); + + // ── OSC Listeners ───────────────────────────────────────────────────────── + server.on("/api/osc/listeners", HTTP_ANY, [](AsyncWebServerRequest* r) { + if (r->method() == HTTP_GET) { + r->send(200, F("application/json"), dpxOscListenersJson()); + return; + } + String body = dpxBody(r); + DynamicJsonDocument doc(256); + if (deserializeJson(doc, body)) { r->send(400, F("text/plain"), F("bad JSON")); return; } + + if (r->method() == HTTP_DELETE) { + String path = doc["path"] | String(); + if (path.length()) { + dpxOscListeners.erase( + std::remove_if(dpxOscListeners.begin(), dpxOscListeners.end(), + [&path](const DpxOscListener& l){ return l.path == path; }), + dpxOscListeners.end()); + dpxSaveOscListeners(); } - if (!found) { DpxOscListener l; l.path=path; l.channel=channel; l.label=label; dpxOscListeners.push_back(l); } - dpxSaveOscListeners(); - r->send(200, "text/plain", "OK"); - }); - - server.on("/api/osc/listeners", HTTP_DELETE, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - StaticJsonDocument<128> doc; - String body((char*)data, len); - if (deserializeJson(doc, body)) { r->send(400, "text/plain", "BadRequest"); return; } - String path = doc["path"].as(); + r->send(200, F("application/json"), F("{\"ok\":true}")); + return; + } + // POST: add listener + DpxOscListener lsr; + lsr.path = doc["path"] | String(); + lsr.channel = doc["channel"] | String(); + lsr.label = doc["label"] | lsr.channel; + if (lsr.path.length() && lsr.channel.length()) { + // Remove any existing entry for this path first dpxOscListeners.erase( std::remove_if(dpxOscListeners.begin(), dpxOscListeners.end(), - [&](const DpxOscListener& l){ return l.path == path; }), + [&lsr](const DpxOscListener& l){ return l.path == lsr.path; }), dpxOscListeners.end()); + dpxOscListeners.push_back(lsr); dpxSaveOscListeners(); - r->send(200, "text/plain", "OK"); - }); + // Ensure target app channel exists + if (dpxCustom.find(lsr.channel) == dpxCustom.end()) { + DpxCustomApp a; a.valid = true; a.text = lsr.label; + dpxCustom[lsr.channel] = a; + dpxRebuildLoop(); + } + } + r->send(200, F("application/json"), F("{\"ok\":true}")); + }); - // Settings passthrough — read/write WLED settings JSON (partial — BRI only for now) - server.on("/api/settings", HTTP_GET, [](AsyncWebServerRequest* r) { + // ── Moodlight ───────────────────────────────────────────────────────────── + // Non-empty body → disable dpx overlay, WLED effects take over + // Empty body → re-enable dpx overlay + server.on("/api/moodlight", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + body.trim(); + if (!body.length() || body == "{}") { + dpxEnabled = true; + r->send(200, F("application/json"), F("{\"ok\":true,\"enabled\":true}")); + return; + } + dpxEnabled = false; + // Apply brightness/color to WLED if provided + DynamicJsonDocument doc(256); + if (!deserializeJson(doc, body)) { + if (doc.containsKey("brightness")) { + bri = (uint8_t)constrain(doc["brightness"].as(), 0, 255); + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + } + r->send(200, F("application/json"), F("{\"ok\":true,\"enabled\":false}")); + }); + + // ── RTTTL / Sound — TC001 piezo buzzer on GPIO 15 ──────────────────────── + // POST /api/rtttl body: raw RTTTL string (e.g. "Beep:d=4,o=5,b=200:c,e,g") + server.on("/api/rtttl", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + body.trim(); + if (body.length()) { + dpxBuzzerPlay(body.c_str()); + r->send(200, F("application/json"), F("{\"ok\":true}")); + } else { + r->send(400, F("text/plain"), F("RTTTL string required")); + } + }); + // POST /api/sound body: JSON {"rtttl":"..."} — compatible with old senders + server.on("/api/sound", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + body.trim(); StaticJsonDocument<256> doc; - doc["BRI"] = bri; - doc["ATIME"] = DPX_ATIME; - doc["ATRANS"] = DPX_ATRANS; - doc["SSPEED"] = DPX_SSPEED; - String s; serializeJson(doc, s); - r->send(200, "application/json", s); + if (!deserializeJson(doc, body) && doc.containsKey("rtttl")) { + String s = doc["rtttl"].as(); + dpxBuzzerPlay(s.c_str()); + r->send(200, F("application/json"), F("{\"ok\":true}")); + } else if (body.startsWith("Beep") || body.indexOf(':') > 0) { + // Plain RTTTL string passed to /api/sound as well + dpxBuzzerPlay(body.c_str()); + r->send(200, F("application/json"), F("{\"ok\":true}")); + } else { + r->send(400, F("text/plain"), F("rtttl field required")); + } }); - server.on("/api/settings", HTTP_POST, [](AsyncWebServerRequest* r) {}, - nullptr, - [](AsyncWebServerRequest* r, uint8_t* data, size_t len, size_t, size_t) { - StaticJsonDocument<512> doc; - String body((char*)data, len); - if (!deserializeJson(doc, body)) { - if (doc.containsKey("BRI")) { bri = doc["BRI"].as(); stateUpdated(CALL_MODE_DIRECT_CHANGE); } - if (doc.containsKey("ATIME")) DPX_ATIME = doc["ATIME"].as(); - if (doc.containsKey("ATRANS")) DPX_ATRANS = doc["ATRANS"].as(); - if (doc.containsKey("SSPEED")) DPX_SSPEED = doc["SSPEED"].as(); - } - r->send(200, "text/plain", "OK"); - }); - // Moodlight — placeholder (WLED handles this differently; delegate to WLED /json endpoint) - server.on("/api/moodlight", HTTP_ANY, [](AsyncWebServerRequest* r) { - r->send(200, "text/plain", "OK"); + // ── File rename ─────────────────────────────────────────────────────────── + // {"from":"/ICONS/a.jpg","to":"/ICONS/b.jpg"} + server.on("/api/rename", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + DynamicJsonDocument doc(256); + if (deserializeJson(doc, body)) { r->send(400, F("text/plain"), F("bad JSON")); return; } + String from = doc["from"] | String(); + String to = doc["to"] | String(); + if (from.isEmpty() || to.isEmpty()) { r->send(400, F("text/plain"), F("from/to required")); return; } + if (!LittleFS.exists(from)) { r->send(404, F("text/plain"), F("not found")); return; } + if (LittleFS.rename(from, to)) { + r->send(200, F("application/json"), F("{\"ok\":true}")); + } else { + r->send(500, F("text/plain"), F("rename failed")); + } }); - // RTTTL — no buzzer in this build; accept and ignore for compatibility - server.on("/api/rtttl", HTTP_POST, [](AsyncWebServerRequest* r) { - r->send(200, "text/plain", "OK"); + // ── WLED effects list ───────────────────────────────────────────────────── + server.on("/api/effects", HTTP_GET, [](AsyncWebServerRequest* r) { + DynamicJsonDocument doc(8192); + JsonArray arr = doc.to(); + uint8_t cnt = strip.getModeCount(); + for (uint8_t i = 0; i < cnt; i++) { + const char* data = strip.getModeData(i); + if (!data) continue; + // Mode string format: "Name@param1,param2;..." — extract up to '@' or ';' or '\0' + String name; + while (*data && *data != '@' && *data != ';') name += *data++; + name.trim(); + if (name.length()) arr.add(name); + } + String s; serializeJson(doc, s); + r->send(200, F("application/json"), s); }); - // Sound — placeholder - server.on("/api/sound", HTTP_ANY, [](AsyncWebServerRequest* r) { - r->send(200, "text/plain", "OK"); + // ── Transitions list (stub — not implemented) ───────────────────────────── + server.on("/api/transitions", HTTP_GET, [](AsyncWebServerRequest* r) { + r->send(200, F("application/json"), F("[]")); }); - // Sleep — WLED handles deep sleep; placeholder - server.on("/api/sleep", HTTP_POST, [](AsyncWebServerRequest* r) { - r->send(200, "text/plain", "OK"); + // ── Reboot ──────────────────────────────────────────────────────────────── + server.on("/dpx/reboot", HTTP_ANY, [](AsyncWebServerRequest* r) { + r->send(200, F("text/plain"), F("OK")); + delay(200); + ESP.restart(); + }); + server.on("/api/reboot", HTTP_ANY, [](AsyncWebServerRequest* r) { + r->send(200, F("application/json"), F("{\"ok\":true}")); + delay(200); + ESP.restart(); }); } diff --git a/usermods/dpx_matrix/dpx_apps.h b/usermods/dpx_matrix/dpx_apps.h index d309a6234d..d035d93b58 100644 --- a/usermods/dpx_matrix/dpx_apps.h +++ b/usermods/dpx_matrix/dpx_apps.h @@ -171,11 +171,10 @@ static void dpxRenderNativeTime() { time_t now; struct tm ti; time(&now); localtime_r(&now, &ti); char buf[9]; - // HH:MM format on 32px wide strftime(buf, sizeof(buf), "%H:%M", &ti); int w = dpxTextPixelWidth(buf); int x = (DPX_MATRIX_W - w) / 2; - dpxRenderText(x, 0, buf, 0xFFFFFF); + dpxRenderText(x, DPX_FONT_BASELINE, buf, 0xFFFFFF); } static void dpxRenderNativeDate() { @@ -185,7 +184,7 @@ static void dpxRenderNativeDate() { strftime(buf, sizeof(buf), "%d.%m.%y", &ti); int w = dpxTextPixelWidth(buf); int x = (DPX_MATRIX_W - w) / 2; - dpxRenderText(x, 0, buf, 0x8888FF); + dpxRenderText(x, DPX_FONT_BASELINE, buf, 0x8888FF); } // ── Render one custom app frame (static or scroll) ─────────────────────────── @@ -357,7 +356,7 @@ static void dpxAppLoopTick() { static void dpxRenderCurrentApp() { if (dpxApps.empty()) { dpxClear(); - dpxRenderText(0, 0, "NO APP", 0x444444); + dpxRenderText(0, DPX_FONT_BASELINE, "NO APP", 0x444444); return; } diff --git a/usermods/dpx_matrix/dpx_firstboot.h b/usermods/dpx_matrix/dpx_firstboot.h index a2f800befd..32bce04616 100644 --- a/usermods/dpx_matrix/dpx_firstboot.h +++ b/usermods/dpx_matrix/dpx_firstboot.h @@ -6,99 +6,102 @@ // PROJECT: dpx_tc002_frm // ================================================================================ // -// File: dpx_firstboot.h -// Purpose: On first boot (no /cfg.json on LittleFS), write a complete default -// configuration for the Ulanzi TC001 hardware so the device is usable -// out of the box without needing the WLED setup wizard. +// Writes /cfg.json on first boot (file absent) so the device is usable +// out of the box without the WLED setup wizard. // -// Pre-configured defaults: -// - LED: GPIO 32, 256 WS2812B, GRB, no 2D yet (set via WLED UI) -// - AP: behav=1 (always open when disconnected, no timeout) -// - AP SSID: dpx-tc002 password: dubpixel1 -// - mDNS: dpx-tc002 -// - Name: dpx_tc002 +// Defaults written: +// AP dpx-tc002 / dubpixel1, behav=1 (always open when disconnected) +// mDNS dpx-tc002 +// LED GPIO 32, 256× WS2812B GRB, 42fps, 8.5W limit +// 2D 32×8 panel, non-serpentine (change via WLED UI if needed) +// Buttons GPIO 26/14/27, push-button type +// Trans 0ms (instant, better for matrix text) // ================================================================================ #pragma once static void dpxFirstBoot() { - // Only run if /cfg.json does not exist (genuine first boot or wiped flash) if (LittleFS.exists(F("/cfg.json"))) return; - DEBUG_PRINTLN(F("DpxMatrix: first boot — writing default cfg.json")); + DEBUG_PRINTLN(F("DpxMatrix: first boot — writing /cfg.json")); - // Write a minimal but complete cfg.json that WLED will load at next boot. - // We use a raw string to keep it readable and avoid ArduinoJson overhead. - // Field reference: wled00/cfg.cpp deserializeConfig() - // - // Key fields set here: - // id.mdns / id.name — hostname and device name - // ap.ssid / ap.psk — AP credentials (behav 1 = always open when disco) - // hw.led.ins — GPIO 32, 256 WS2812B GRB - // hw.btn.ins — left=GPIO26 short-press (type 2 = push button) - // light.tr.dur — transition duration 0 (instant, better for matrix) + DynamicJsonDocument doc(2048); - File f = LittleFS.open(F("/cfg.json"), "w"); - if (!f) { - DEBUG_PRINTLN(F("DpxMatrix: failed to open /cfg.json for writing")); - return; - } - - f.print(F( - "{" - "\"rev\":[1,0]," - "\"id\":{" - "\"mdns\":\"dpx-tc002\"," - "\"name\":\"dpx_tc002\"," - "\"inv\":\"TC001\"," - "\"sui\":false" - "}," - "\"ap\":{" - "\"ssid\":\"dpx-tc002\"," - "\"psk\":\"dubpixel1\"," - "\"chan\":6," - "\"hide\":0," - "\"behav\":1" - "}," - "\"wifi\":{\"sleep\":false}," - "\"hw\":{" - "\"led\":{" - "\"total\":256," - "\"maxpwr\":8500," - "\"fps\":42," - "\"ins\":[{" - "\"start\":0," - "\"len\":256," - "\"pin\":[32]," - "\"order\":0," - "\"rev\":false," - "\"skip\":0," - "\"type\":22," - "\"ref\":false," - "\"rgbwm\":255," - "\"freq\":0," - "\"ledma\":55," - "\"drv\":0" - "}]" - "}," - "\"btn\":{" - "\"max\":3," - "\"pull\":true," - "\"ins\":[" - "{\"type\":2,\"pin\":[26],\"macros\":[0,0,0]}," - "{\"type\":2,\"pin\":[14],\"macros\":[0,0,0]}," - "{\"type\":2,\"pin\":[27],\"macros\":[0,0,0]}" - "]" - "}" - "}," - "\"light\":{" - "\"tr\":{\"dur\":0,\"rpc\":5,\"hrp\":false}" - "}," - "\"def\":{\"ps\":0,\"on\":true,\"bri\":128}," - "\"ota\":{\"lock\":false}" - "}" - )); + // Identity + JsonObject id = doc.createNestedObject("id"); + id["mdns"] = "dpx-tc002"; + id["name"] = "dpx_tc002"; + id["inv"] = "TC001"; + id["sui"] = false; + + // Access point + JsonObject ap = doc.createNestedObject("ap"); + ap["ssid"] = "dpx-tc002"; + ap["psk"] = "dubpixel1"; + ap["chan"] = 6; + ap["hide"] = 0; + ap["behav"] = 1; // AP_BEHAVIOR_NO_CONN — always open when disconnected + + // WiFi + doc["wifi"]["sleep"] = false; + + // Hardware — LED + JsonObject hw = doc.createNestedObject("hw"); + JsonObject led = hw.createNestedObject("led"); + led["total"] = 256; + led["maxpwr"] = 8500; + led["fps"] = 42; + + JsonObject ins = led["ins"].createNestedObject(); + ins["start"] = 0; + ins["len"] = 256; + ins["pin"][0] = 32; + ins["order"] = 0; // GRB + ins["rev"] = false; + ins["skip"] = 0; + ins["type"] = 22; // TYPE_WS2812_RGB + ins["ref"] = false; + ins["rgbwm"] = 255; + ins["freq"] = 0; + ins["ledma"] = 55; + ins["drv"] = 0; + + // 2D matrix — 32×8, non-serpentine (user can toggle serpentine in WLED UI) + JsonObject matrix = led.createNestedObject("matrix"); + matrix["mpc"] = 1; + JsonObject panel = matrix["panels"].createNestedObject(); + panel["b"] = false; // top start + panel["r"] = false; // left start + panel["v"] = false; // horizontal + panel["s"] = false; // serpentine — set true in WLED UI if needed + panel["x"] = 0; + panel["y"] = 0; + panel["h"] = 8; + panel["w"] = 32; + // Hardware — buttons + JsonObject btn = hw.createNestedObject("btn"); + btn["max"] = 3; + btn["pull"] = true; + JsonObject b0 = btn["ins"].createNestedObject(); b0["type"]=2; b0["pin"][0]=26; b0["macros"][0]=0; b0["macros"][1]=0; b0["macros"][2]=0; + JsonObject b1 = btn["ins"].createNestedObject(); b1["type"]=2; b1["pin"][0]=14; b1["macros"][0]=0; b1["macros"][1]=0; b1["macros"][2]=0; + JsonObject b2 = btn["ins"].createNestedObject(); b2["type"]=2; b2["pin"][0]=27; b2["macros"][0]=0; b2["macros"][1]=0; b2["macros"][2]=0; + + // Light — instant transitions + doc["light"]["tr"]["dur"] = 0; + doc["light"]["tr"]["rpc"] = 5; + + // Defaults + doc["def"]["ps"] = 0; + doc["def"]["on"] = true; + doc["def"]["bri"] = 128; + + doc["ota"]["lock"] = false; + + File f = LittleFS.open(F("/cfg.json"), "w"); + if (!f) { DEBUG_PRINTLN(F("DpxMatrix: failed to open /cfg.json")); return; } + serializeJson(doc, f); f.close(); - DEBUG_PRINTLN(F("DpxMatrix: default cfg.json written — reboot to apply")); + DEBUG_PRINTLN(F("DpxMatrix: /cfg.json written — takes effect on next boot")); } + diff --git a/usermods/dpx_matrix/dpx_font.h b/usermods/dpx_matrix/dpx_font.h index 77efcd025e..b2b089e3c7 100644 --- a/usermods/dpx_matrix/dpx_font.h +++ b/usermods/dpx_matrix/dpx_font.h @@ -1,146 +1,542 @@ // ================================================================================ -// dpx_font.h — 5×7 Pixel Bitmap Font +// dpx_font.h — AwtrixFont (TomThumb-derived 3x5 pixel font) // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) -// NOT derived from AwtrixFont.h (CC BY-NC-SA 4.0). Written from scratch. +// +// License: BSD 3-Clause (see full text below) +// +// Original 3x5 font: Brian J. Swetland, Vassilii Khachaturov (1999) +// TomThumb modifications: Robey Pointer (2010) — http://robey.lag.net/2010/01/23/tiny-monospace-font.html +// AWTRIX modifications for improved readability: Blueforcer (2018–2024) +// GFX conversion: William Skellenger (2016) +// +// Redistributed under the BSD 3-Clause License. Attribution retained above. +// See: http://opengameart.org/forumtopic/how-to-submit-art-using-the-3-clause-bsd-license +// // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ // // File: dpx_font.h -// Purpose: 5-wide × 7-tall pixel font for 32×8 LED matrix display. -// Column-major storage: 5 bytes per glyph, each byte = 1 column. -// Bit 0 = top row, Bit 6 = bottom row. Bit 7 unused. -// Covers printable ASCII 0x20 (space) through 0x7E (~). +// Purpose: Inline GFX-format font data + lightweight lookup helpers. +// Used by dpx_text.h for rendering text onto the 32x8 LED matrix. // -// Usage: -// const uint8_t *glyph = dpxFontGlyph('A'); // returns 5-byte pointer -// uint8_t col0 = glyph[0]; // leftmost column bitmap +// Font metrics (per glyph, all glyphs): +// Height: 5 pixels (yOffset = -5 from baseline) +// yAdvance: 6 (line height; only 1 row used currently) +// Baseline: set cursor_y = DPX_FONT_BASELINE (= 6) to center in 8-row display +// → glyph rows land on matrix rows 1..5, leaving row 0 and rows 6..7 clear +// xAdvance: variable (2..4 px) includes 1-px right gap // // ================================================================================ #pragma once -#include -// Glyph width in pixels (columns) -static const uint8_t DPX_FONT_W = 5; -// Glyph height in pixels (rows) -static const uint8_t DPX_FONT_H = 7; -// Gap between characters in pixels -static const uint8_t DPX_FONT_GAP = 1; +// ── Adafruit GFX font structs (defined here; WLED does not bundle Adafruit GFX) ── +#ifndef _GFXFONT_H_ +#define _GFXFONT_H_ +typedef struct { + uint16_t bitmapOffset; // Pointer into GFXfont->bitmap + uint8_t width; // Bitmap dimensions in pixels + uint8_t height; + uint8_t xAdvance; // Distance to advance cursor (x axis) + int8_t xOffset; // X dist from cursor to UL corner + int8_t yOffset; // Y dist from cursor to UL corner (negative = up) +} GFXglyph; + +typedef struct { + uint8_t *bitmap; // Glyph bitmaps, concatenated + GFXglyph *glyph; // Glyph array + uint16_t first; // ASCII extents (first char) + uint16_t last; // ASCII extents (last char) + uint8_t yAdvance; // Newline distance (y axis) +} GFXfont; +#endif // _GFXFONT_H_ + +// ── Font constants ───────────────────────────────────────────────────────────── +#define DPX_FONT_H 5 // Glyph height in pixels +#define DPX_FONT_BASELINE 6 // cursor_y to center glyph in 8-row display + -// 5×7 bitmap font — column-major, LSB = top row. -// 95 characters, ASCII 0x20 (space) to 0x7E (~). -// Each row: 5 column bytes for one character. -static const uint8_t DPX_FONT[95][5] PROGMEM = { - {0x00,0x00,0x00,0x00,0x00}, // 0x20 space - {0x00,0x00,0x5F,0x00,0x00}, // 0x21 ! - {0x00,0x07,0x00,0x07,0x00}, // 0x22 " - {0x14,0x7F,0x14,0x7F,0x14}, // 0x23 # - {0x24,0x2A,0x7F,0x2A,0x12}, // 0x24 $ - {0x23,0x13,0x08,0x64,0x62}, // 0x25 % - {0x36,0x49,0x55,0x22,0x50}, // 0x26 & - {0x00,0x05,0x03,0x00,0x00}, // 0x27 ' - {0x00,0x1C,0x22,0x41,0x00}, // 0x28 ( - {0x00,0x41,0x22,0x1C,0x00}, // 0x29 ) - {0x08,0x2A,0x1C,0x2A,0x08}, // 0x2A * - {0x08,0x08,0x3E,0x08,0x08}, // 0x2B + - {0x00,0x50,0x30,0x00,0x00}, // 0x2C , - {0x08,0x08,0x08,0x08,0x08}, // 0x2D - - {0x00,0x60,0x60,0x00,0x00}, // 0x2E . - {0x20,0x10,0x08,0x04,0x02}, // 0x2F / - {0x3E,0x51,0x49,0x45,0x3E}, // 0x30 0 - {0x00,0x42,0x7F,0x40,0x00}, // 0x31 1 - {0x42,0x61,0x51,0x49,0x46}, // 0x32 2 - {0x21,0x41,0x45,0x4B,0x31}, // 0x33 3 - {0x18,0x14,0x12,0x7F,0x10}, // 0x34 4 - {0x27,0x45,0x45,0x45,0x39}, // 0x35 5 - {0x3C,0x4A,0x49,0x49,0x30}, // 0x36 6 - {0x01,0x71,0x09,0x05,0x03}, // 0x37 7 - {0x36,0x49,0x49,0x49,0x36}, // 0x38 8 - {0x06,0x49,0x49,0x29,0x1E}, // 0x39 9 - {0x00,0x36,0x36,0x00,0x00}, // 0x3A : - {0x00,0x56,0x36,0x00,0x00}, // 0x3B ; - {0x08,0x14,0x22,0x41,0x00}, // 0x3C < - {0x14,0x14,0x14,0x14,0x14}, // 0x3D = - {0x00,0x41,0x22,0x14,0x08}, // 0x3E > - {0x02,0x01,0x51,0x09,0x06}, // 0x3F ? - {0x32,0x49,0x79,0x41,0x3E}, // 0x40 @ - {0x7E,0x11,0x11,0x11,0x7E}, // 0x41 A - {0x7F,0x49,0x49,0x49,0x36}, // 0x42 B - {0x3E,0x41,0x41,0x41,0x22}, // 0x43 C - {0x7F,0x41,0x41,0x22,0x1C}, // 0x44 D - {0x7F,0x49,0x49,0x49,0x41}, // 0x45 E - {0x7F,0x09,0x09,0x09,0x01}, // 0x46 F - {0x3E,0x41,0x49,0x49,0x7A}, // 0x47 G - {0x7F,0x08,0x08,0x08,0x7F}, // 0x48 H - {0x00,0x41,0x7F,0x41,0x00}, // 0x49 I - {0x20,0x40,0x41,0x3F,0x01}, // 0x4A J - {0x7F,0x08,0x14,0x22,0x41}, // 0x4B K - {0x7F,0x40,0x40,0x40,0x40}, // 0x4C L - {0x7F,0x02,0x0C,0x02,0x7F}, // 0x4D M - {0x7F,0x04,0x08,0x10,0x7F}, // 0x4E N - {0x3E,0x41,0x41,0x41,0x3E}, // 0x4F O - {0x7F,0x09,0x09,0x09,0x06}, // 0x50 P - {0x3E,0x41,0x51,0x21,0x5E}, // 0x51 Q - {0x7F,0x09,0x19,0x29,0x46}, // 0x52 R - {0x46,0x49,0x49,0x49,0x31}, // 0x53 S - {0x01,0x01,0x7F,0x01,0x01}, // 0x54 T - {0x3F,0x40,0x40,0x40,0x3F}, // 0x55 U - {0x1F,0x20,0x40,0x20,0x1F}, // 0x56 V - {0x3F,0x40,0x38,0x40,0x3F}, // 0x57 W - {0x63,0x14,0x08,0x14,0x63}, // 0x58 X - {0x07,0x08,0x70,0x08,0x07}, // 0x59 Y - {0x61,0x51,0x49,0x45,0x43}, // 0x5A Z - {0x00,0x7F,0x41,0x41,0x00}, // 0x5B [ - {0x02,0x04,0x08,0x10,0x20}, // 0x5C backslash - {0x00,0x41,0x41,0x7F,0x00}, // 0x5D ] - {0x04,0x02,0x01,0x02,0x04}, // 0x5E ^ - {0x40,0x40,0x40,0x40,0x40}, // 0x5F _ - {0x00,0x01,0x02,0x04,0x00}, // 0x60 ` - {0x20,0x54,0x54,0x54,0x78}, // 0x61 a - {0x7F,0x48,0x44,0x44,0x38}, // 0x62 b - {0x38,0x44,0x44,0x44,0x20}, // 0x63 c - {0x38,0x44,0x44,0x48,0x7F}, // 0x64 d - {0x38,0x54,0x54,0x54,0x18}, // 0x65 e - {0x08,0x7E,0x09,0x01,0x02}, // 0x66 f - {0x0C,0x52,0x52,0x52,0x3E}, // 0x67 g - {0x7F,0x08,0x04,0x04,0x78}, // 0x68 h - {0x00,0x44,0x7D,0x40,0x00}, // 0x69 i - {0x20,0x40,0x44,0x3D,0x00}, // 0x6A j - {0x7F,0x10,0x28,0x44,0x00}, // 0x6B k - {0x00,0x41,0x7F,0x40,0x00}, // 0x6C l - {0x7C,0x04,0x18,0x04,0x78}, // 0x6D m - {0x7C,0x08,0x04,0x04,0x78}, // 0x6E n - {0x38,0x44,0x44,0x44,0x38}, // 0x6F o - {0x7C,0x14,0x14,0x14,0x08}, // 0x70 p - {0x08,0x14,0x14,0x18,0x7C}, // 0x71 q - {0x7C,0x08,0x04,0x04,0x00}, // 0x72 r - {0x48,0x54,0x54,0x54,0x20}, // 0x73 s - {0x04,0x3F,0x44,0x40,0x20}, // 0x74 t - {0x3C,0x40,0x40,0x20,0x7C}, // 0x75 u - {0x1C,0x20,0x40,0x20,0x1C}, // 0x76 v - {0x3C,0x40,0x30,0x40,0x3C}, // 0x77 w - {0x44,0x28,0x10,0x28,0x44}, // 0x78 x - {0x0C,0x50,0x50,0x50,0x3C}, // 0x79 y - {0x44,0x64,0x54,0x4C,0x44}, // 0x7A z - {0x00,0x08,0x36,0x41,0x00}, // 0x7B { - {0x00,0x00,0x7F,0x00,0x00}, // 0x7C | - {0x00,0x41,0x36,0x08,0x00}, // 0x7D } - {0x10,0x08,0x08,0x10,0x08}, // 0x7E ~ +// AwtrixFont Version 20240129 + +const uint8_t AwtrixBitmaps[] PROGMEM = { + 0x00, /*[0] 0x20 space */ + 0x80, 0x80, 0x80, 0x00, 0x80, /*[1] 0x21 exclam */ + 0xA0, 0xA0, /*[2] 0x22 quotedbl */ + 0xA0, 0xE0, 0xA0, 0xE0, 0xA0, /*[3] 0x23 numbersign */ + 0x60, 0xC0, 0x60, 0xC0, 0x40, /*[4] 0x24 dollar */ + 0xA0, 0x20, 0x40, 0x80, 0xA0, /*[5] 0x25 percent */ + 0xC0, 0xC0, 0xE0, 0xA0, 0x60, /*[6] 0x26 ampersand */ + 0x80, 0x80, /*[7] 0x27 quotesingle */ + 0x40, 0x80, 0x80, 0x80, 0x40, /*[8] 0x28 parenleft */ + 0x80, 0x40, 0x40, 0x40, 0x80, /*[9] 0x29 parenright */ + 0xA0, 0x40, 0xA0, /*[10] 0x2A asterisk */ + 0x40, 0xE0, 0x40, /*[11] 0x2B plus */ + 0x40, 0x80, /*[12] 0x2C comma */ + 0xE0, /*[13] 0x2D hyphen */ + 0x80, /*[14] 0x2E period */ + 0x20, 0x20, 0x40, 0x80, 0x80, /*[15] 0x2F slash */ + 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, /*[16] 0x30 zero */ + 0x40, 0xC0, 0x40, 0x40, 0xE0, /*[17] 0x31 one */ + 0xE0, 0x20, 0xE0, 0x80, 0xE0, /*[18] 0x32 two */ + 0xE0, 0x20, 0xE0, 0x20, 0xE0, /*[19] 0x33 three */ + 0xA0, 0xA0, 0xE0, 0x20, 0x20, /*[20] 0x34 four */ + 0xE0, 0x80, 0xE0, 0x20, 0xE0, /*[21] 0x35 five */ + 0xE0, 0x80, 0xE0, 0xA0, 0xE0, /*[22] 0x36 six */ + 0xE0, 0x20, 0x20, 0x20, 0x20, /*[23] 0x37 seven */ + 0xE0, 0xA0, 0xE0, 0xA0, 0xE0, /*[24] 0x38 eight */ + 0xE0, 0xA0, 0xE0, 0x20, 0xE0, /*[25] 0x39 nine */ + 0x80, 0x00, 0x80, /*[26] 0x3A colon */ + 0x40, 0x00, 0x40, 0x80, /*[27] 0x3B semicolon */ + 0x20, 0x40, 0x80, 0x40, 0x20, /*[28] 0x3C less */ + 0xE0, 0x00, 0xE0, /*[29] 0x3D equal */ + 0x80, 0x40, 0x20, 0x40, 0x80, /*[30] 0x3E greater */ + 0xE0, 0x20, 0x40, 0x00, 0x40, /*[31] 0x3F question */ + 0x40, 0xA0, 0xE0, 0x80, 0x60, /*[32] 0x40 at */ + 0xC0, 0xA0, 0xE0, 0xA0, 0xA0, /*[33] 0x41 A */ + 0xC0, 0xA0, 0xC0, 0xA0, 0xC0, /*[34] 0x42 B */ + 0x40, 0xA0, 0x80, 0xA0, 0x40, /*[35] 0x43 C */ + 0xC0, 0xA0, 0xA0, 0xA0, 0xC0, /*[36] 0x44 D */ + 0xE0, 0x80, 0xE0, 0x80, 0xE0, /*[37] 0x45 E */ + 0xE0, 0x80, 0xE0, 0x80, 0x80, /*[38] 0x46 F */ + 0x60, 0x80, 0xA0, 0xA0, 0x60, /*[39] 0x47 G */ + 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, /*[40] 0x48 H */ + 0x80, 0x80, 0x80, 0x80, 0x80, /*[41] 0x49 I */ + 0x20, 0x20, 0x20, 0xA0, 0x40, /*[42] 0x4A J */ + 0xA0, 0xA0, 0xC0, 0xA0, 0xA0, /*[43] 0x4B K */ + 0x80, 0x80, 0x80, 0x80, 0xE0, /*[44] 0x4C L */ + 0x88, 0xD8, 0xA8, 0x88, 0x88, /*[45] 0x4D M */ + 0x90, 0xD0, 0xB0, 0x90, 0x90, /*[46] 0x4E N */ + 0x40, 0xA0, 0xA0, 0xA0, 0x40, /*[47] 0x4F O */ + 0xE0, 0xA0, 0xC0, 0x80, 0x80, /*[48] 0x50 P */ + 0x40, 0xA0, 0xA0, 0xA0, 0x70, /*[49] 0x51 Q */ + 0xE0, 0xA0, 0xC0, 0xA0, 0xA0, /*[50] 0x52 R */ + 0xE0, 0x80, 0xE0, 0x20, 0xE0, /*[51] 0x53 S */ + 0xE0, 0x40, 0x40, 0x40, 0x40, /*[52] 0x54 T */ + 0xA0, 0xA0, 0xA0, 0xA0, 0xE0, /*[53] 0x55 U */ + 0xA0, 0xA0, 0xA0, 0xA0, 0x40, /*[54] 0x56 V */ + 0x88, 0x88, 0x88, 0xA8, 0x50, /*[55] 0x57 W */ + 0xA0, 0xA0, 0x40, 0xA0, 0xA0, /*[56] 0x58 X */ + 0xA0, 0xA0, 0xE0, 0x20, 0xC0, /*[57] 0x59 Y */ + 0xE0, 0x20, 0x40, 0x80, 0xE0, /*[58] 0x5A Z */ + 0xE0, 0x80, 0x80, 0x80, 0xE0, /*[59] 0x5B bracketleft */ + 0x80, 0x40, 0x20, /*[60] 0x5C backslash */ + 0xE0, 0x20, 0x20, 0x20, 0xE0, /*[61] 0x5D bracketright */ + 0x40, 0xA0, /*[62] 0x5E asciicircum */ + 0xE0, /*[63] 0x5F underscore */ + 0x80, 0x40, /*[64] 0x60 grave */ + 0xC0, 0x60, 0xA0, 0xE0, /*[65] 0x61 a */ + 0x80, 0xC0, 0xA0, 0xA0, 0xC0, /*[66] 0x62 b */ + 0x60, 0x80, 0x80, 0x60, /*[67] 0x63 c */ + 0x20, 0x60, 0xA0, 0xA0, 0x60, /*[68] 0x64 d */ + 0x60, 0xA0, 0xC0, 0x60, /*[69] 0x65 e */ + 0x20, 0x40, 0xE0, 0x40, 0x40, /*[70] 0x66 f */ + 0x60, 0xA0, 0xE0, 0x20, 0x40, /*[71] 0x67 g */ + 0x80, 0xC0, 0xA0, 0xA0, 0xA0, /*[72] 0x68 h */ + 0x80, 0x00, 0x80, 0x80, 0x80, /*[73] 0x69 i */ + 0x20, 0x00, 0x20, 0x20, 0xA0, 0x40, /*[74] 0x6A j */ + 0x80, 0xA0, 0xC0, 0xC0, 0xA0, /*[75] 0x6B k */ + 0xC0, 0x40, 0x40, 0x40, 0xE0, /*[76] 0x6C l */ + 0xE0, 0xE0, 0xE0, 0xA0, /*[77] 0x6D m */ + 0xC0, 0xA0, 0xA0, 0xA0, /*[78] 0x6E n */ + 0x40, 0xA0, 0xA0, 0x40, /*[79] 0x6F o */ + 0xC0, 0xA0, 0xA0, 0xC0, 0x80, /*[80] 0x70 p */ + 0x60, 0xA0, 0xA0, 0x60, 0x20, /*[81] 0x71 q */ + 0x60, 0x80, 0x80, 0x80, /*[82] 0x72 r */ + 0x60, 0xC0, 0x60, 0xC0, /*[83] 0x73 s */ + 0x40, 0xE0, 0x40, 0x40, 0x60, /*[84] 0x74 t */ + 0xA0, 0xA0, 0xA0, 0x60, /*[85] 0x75 u */ + 0xA0, 0xA0, 0xE0, 0x40, /*[86] 0x76 v */ + 0xA0, 0xE0, 0xE0, 0xE0, /*[87] 0x77 w */ + 0xA0, 0x40, 0x40, 0xA0, /*[88] 0x78 x */ + 0xA0, 0xA0, 0x60, 0x20, 0x40, /*[89] 0x79 y */ + 0xE0, 0x60, 0xC0, 0xE0, /*[90] 0x7A z */ + 0x60, 0x40, 0x80, 0x40, 0x60, /*[91] 0x7B braceleft */ + 0x80, 0x80, 0x80, 0x80, 0x80, /*[92] 0x7C bar */ + 0xC0, 0x40, 0x20, 0x40, 0xC0, /*[93] 0x7D braceright */ + 0x60, 0xC0, /*[94] 0x7E asciitilde */ + + 0xE0, 0xA0, 0xE0, 0xA0, 0xA0, /*[95] 0x7F А */ + 0xE0, 0x80, 0xE0, 0xA0, 0xE0, /*[96] 0x80 Б */ + 0xC0, 0xA0, 0xE0, 0xA0, 0xC0, /*[97] 0x81 В */ + 0xE0, 0x80, 0x80, 0x80, 0x80, /*[98] 0x82 Г */ + 0x70, 0x50, 0x50, 0x50, 0xF8, /*[99] 0x83 Д */ + 0xE0, 0x80, 0xC0, 0x80, 0xE0, /*[100] 0x84 Е */ + 0xA8, 0xA8, 0x70, 0xA8, 0xA8, /*[101] 0x85 Ж */ + 0xC0, 0x20, 0x40, 0x20, 0xC0, /*[102] 0x86 З */ + 0x90, 0x90, 0xB0, 0xD0, 0x90, /*[103] 0x87 И */ + 0x20, 0x90, 0xB0, 0xD0, 0x90, /*[104] 0x88 Й */ + 0xA0, 0xA0, 0xC0, 0xA0, 0xA0, /*[105] 0x89 К */ + 0x60, 0xA0, 0xA0, 0xA0, 0xA0, /*[106] 0x8A Л */ + 0x88, 0xD8, 0xA8, 0x88, 0x88, /*[107] 0x8B М */ + 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, /*[108] 0x8C Н */ + 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, /*[109] 0x8D О */ + 0xE0, 0xA0, 0xA0, 0xA0, 0xA0, /*[110] 0x8E П */ + 0xE0, 0xA0, 0xE0, 0x80, 0x80, /*[111] 0x8F Р */ + 0xE0, 0x80, 0x80, 0x80, 0xE0, /*[112] 0x90 С */ + 0xE0, 0x40, 0x40, 0x40, 0x40, /*[113] 0x91 Т */ + 0xA0, 0xA0, 0xE0, 0x20, 0xC0, /*[114] 0x92 У */ + 0xF8, 0xA8, 0xF8, 0x20, 0x20, /*[115] 0x93 Ф */ + 0xA0, 0xA0, 0x40, 0xA0, 0xA0, /*[116] 0x94 Х */ + 0xA0, 0xA0, 0xA0, 0xA0, 0xF0, /*[117] 0x95 Ц */ + 0xA0, 0xA0, 0xE0, 0x20, 0x20, /*[118] 0x96 Ч */ + 0xA8, 0xA8, 0xA8, 0xA8, 0xF8, /*[119] 0x97 Ш */ + 0xA8, 0xA8, 0xA8, 0xA8, 0xFC, /*[120] 0x98 Щ */ + 0xC0, 0x40, 0x70, 0x50, 0x70, /*[121] 0x99 Ъ */ + 0x88, 0x88, 0xE8, 0xA8, 0xE8, /*[122] 0x9A Ы */ + 0x80, 0x80, 0xE0, 0xA0, 0xE0, /*[123] 0x9B Ь */ + 0xC0, 0x20, 0x60, 0x20, 0xC0, /*[124] 0x9C Э */ + 0xB8, 0xA8, 0xE8, 0xA8, 0xB8, /*[125] 0x9D Ю */ + 0xE0, 0xA0, 0x60, 0xA0, 0xA0, /*[126] 0x9E Я */ + 0x20, 0xE0, 0x80, 0x80, 0x80, 0x00, 0x00, /*[127] 0x9F Ґ */ + 0x60, 0x80, 0xC0, 0x80, 0x60, /*[128] 0xA0 Є */ + + 0x80, 0x00, 0x80, 0x80, 0x80, /*[129] 0xA1 exclamdown */ + 0x40, 0xE0, 0x80, 0xE0, 0x40, /*[130] 0xA2 cent */ + 0x60, 0x40, 0xE0, 0x40, 0xE0, /*[131] 0xA3 sterling */ + 0xA0, 0x40, 0xE0, 0x40, 0xA0, /*[132] 0xA4 currency */ + 0xA0, 0xA0, 0x40, 0xE0, 0x40, /*[133] 0xA5 yen */ + 0x80, 0x80, 0x00, 0x80, 0x80, /*[134] 0xA6 brokenbar */ + 0x60, 0x40, 0xA0, 0x40, 0xC0, /*[135] 0xA7 section */ + 0xA0, /*[136] 0xA8 dieresis */ + 0x60, 0x80, 0x60, /*[137] 0xA9 copyright */ + 0x60, 0xA0, 0xE0, 0x00, 0xE0, /*[138] 0xAA ordfeminine */ + 0x40, 0x80, 0x40, /*[139] 0xAB guillemotleft */ + 0xE0, 0x20, /*[140] 0xAC logicalnot */ + 0xC0, /*[141] 0xAD softhyphen */ + 0xC0, 0xC0, 0xA0, /*[142] 0xAE registered */ + 0xE0, /*[143] 0xAF macron */ + 0xC0, 0xC0, 0x00, /*[144] 0xB0 degree */ + 0x40, 0xE0, 0x40, 0x00, 0xE0, /*[145] 0xB1 plusminus */ + 0xC0, 0x40, 0x60, /*[146] 0xB2 twosuperior */ + 0xE0, 0x60, 0xE0, /*[147] 0xB3 threesuperior */ + 0x40, 0x80, /*[148] 0xB4 acute */ + 0xA0, 0xA0, 0xA0, 0xC0, 0x80, /*[149] 0xB5 mu */ + // 0x60, 0xA0, 0x60, 0x60, 0x60, /*[150] 0xB6 paragraph */ + 0x60, 0xC0, 0xE0, 0xC0, 0x60, /*[150] 0x20AC Euro */ + 0xE0, 0xE0, 0xE0, /*[151] 0xB7 periodcentered */ + 0x40, 0x20, 0xC0, /*[152] 0xB8 cedilla */ + 0x80, 0x80, 0x80, /*[153] 0xB9 onesuperior */ + 0x40, 0xA0, 0x40, 0x00, 0xE0, /*[154] 0xBA ordmasculine */ + 0x80, 0x40, 0x80, /*[155] 0xBB guillemotright */ + 0x80, 0x80, 0x00, 0x60, 0x20, /*[156] 0xBC onequarter */ + 0x80, 0x80, 0x00, 0xC0, 0x60, /*[157] 0xBD onehalf */ + 0xC0, 0xC0, 0x00, 0x60, 0x20, /*[158] 0xBE threequarters */ + 0x40, 0x00, 0x40, 0x80, 0xE0, /*[159] 0xBF questiondown */ + 0x40, 0x20, 0x40, 0xE0, 0xA0, /*[160] 0xC0 Agrave */ + 0x40, 0x80, 0x40, 0xE0, 0xA0, /*[161] 0xC1 Aacute */ + 0xE0, 0x00, 0x40, 0xE0, 0xA0, /*[162] 0xC2 Acircumflex */ + 0x60, 0xC0, 0x40, 0xE0, 0xA0, /*[163] 0xC3 Atilde */ + 0xA0, 0x40, 0xA0, 0xE0, 0xA0, /*[164] 0xC4 Adieresis */ + 0xC0, 0xC0, 0xA0, 0xE0, 0xA0, /*[165] 0xC5 Aring */ + 0x60, 0xC0, 0xE0, 0xC0, 0xE0, /*[166] 0xC6 AE */ + 0x60, 0x80, 0x80, 0x60, 0x20, 0x40, /*[167] 0xC7 Ccedilla */ + 0x40, 0x20, 0xE0, 0xC0, 0xE0, /*[168] 0xC8 Egrave */ + 0x40, 0x80, 0xE0, 0xC0, 0xE0, /*[169] 0xC9 Eacute */ + 0xE0, 0x00, 0xE0, 0xC0, 0xE0, /*[170] 0xCA Ecircumflex */ + 0xA0, 0x00, 0xE0, 0xC0, 0xE0, /*[171] 0xCB Edieresis */ + 0x40, 0x20, 0xE0, 0x40, 0xE0, /*[172] 0xCC Igrave */ + 0x40, 0x80, 0xE0, 0x40, 0xE0, /*[173] 0xCD Iacute */ + 0xE0, 0x00, 0xE0, 0x40, 0xE0, /*[174] 0xCE Icircumflex */ + 0xA0, 0x00, 0xE0, 0x40, 0xE0, /*[175] 0xCF Idieresis */ + 0xC0, 0xA0, 0xE0, 0xA0, 0xC0, /*[176] 0xD0 Eth */ + 0xC0, 0x60, 0xA0, 0xE0, 0xA0, /*[177] 0xD1 Ntilde */ + 0x40, 0x20, 0xE0, 0xA0, 0xE0, /*[178] 0xD2 Ograve */ + 0x40, 0x80, 0xE0, 0xA0, 0xE0, /*[179] 0xD3 Oacute */ + 0xE0, 0x00, 0xE0, 0xA0, 0xE0, /*[180] 0xD4 Ocircumflex */ + 0xC0, 0x60, 0xE0, 0xA0, 0xE0, /*[181] 0xD5 Otilde */ + 0xA0, 0x00, 0xE0, 0xA0, 0xE0, /*[182] 0xD6 Odieresis */ + 0xA0, 0x40, 0xA0, /*[183] 0xD7 multiply */ + 0x60, 0xA0, 0xE0, 0xA0, 0xC0, /*[184] 0xD8 Oslash */ + 0x80, 0x40, 0xA0, 0xA0, 0xE0, /*[185] 0xD9 Ugrave */ + 0x20, 0x40, 0xA0, 0xA0, 0xE0, /*[186] 0xDA Uacute */ + 0xE0, 0x00, 0xA0, 0xA0, 0xE0, /*[187] 0xDB Ucircumflex */ + 0xA0, 0x00, 0xA0, 0xA0, 0xE0, /*[188] 0xDC Udieresis */ + 0x20, 0x40, 0xA0, 0xE0, 0x40, /*[189] 0xDD Yacute */ + 0x80, 0xE0, 0xA0, 0xE0, 0x80, /*[190] 0xDE Thorn */ + 0x60, 0xA0, 0xC0, 0xA0, 0xC0, 0x80, /*[191] 0xDF germandbls */ + 0x40, 0x20, 0x60, 0xA0, 0xE0, /*[192] 0xE0 agrave */ + 0x40, 0x80, 0x60, 0xA0, 0xE0, /*[193] 0xE1 aacute */ + 0xE0, 0x00, 0x60, 0xA0, 0xE0, /*[194] 0xE2 acircumflex */ + 0x60, 0xC0, 0x60, 0xA0, 0xE0, /*[195] 0xE3 atilde */ + 0xA0, 0x00, 0x60, 0xA0, 0xE0, /*[196] 0xE4 adieresis */ + 0x60, 0x60, 0x60, 0xA0, 0xE0, /*[197] 0xE5 aring */ + 0x60, 0xE0, 0xE0, 0xC0, /*[198] 0xE6 ae */ + 0x60, 0x80, 0x60, 0x20, 0x40, /*[199] 0xE7 copy&pasteistrash */ + 0x40, 0x20, 0x60, 0xE0, 0x60, /*[200] 0xE8 egrave */ + 0x40, 0x80, 0x60, 0xE0, 0x60, /*[201] 0xE9 eacute */ + 0xE0, 0x00, 0x60, 0xE0, 0x60, /*[202] 0xEA ecircumflex */ + 0xA0, 0x00, 0x60, 0xE0, 0x60, /*[203] 0xEB edieresis */ + 0x80, 0x40, 0x80, 0x80, 0x80, /*[204] 0xEC igrave */ + 0x40, 0x80, 0x40, 0x40, 0x40, /*[205] 0xED iacute */ + 0xE0, 0x00, 0x40, 0x40, 0x40, /*[206] 0xEE icircumflex */ + 0xA0, 0x00, 0x40, 0x40, 0x40, /*[207] 0xEF idieresis */ + 0x60, 0xC0, 0x60, 0xA0, 0x60, /*[208] 0xF0 eth */ + 0xC0, 0x60, 0xC0, 0xA0, 0xA0, /*[209] 0xF1 ntilde */ + 0x40, 0x20, 0x40, 0xA0, 0x40, /*[210] 0xF2 ograve */ + 0x40, 0x80, 0x40, 0xA0, 0x40, /*[211] 0xF3 oacute */ + 0xE0, 0x00, 0x40, 0xA0, 0x40, /*[212] 0xF4 ocircumflex */ + 0xC0, 0x60, 0x40, 0xA0, 0x40, /*[213] 0xF5 otilde */ + 0xA0, 0x00, 0x40, 0xA0, 0x40, /*[214] 0xF6 odieresis */ + 0x40, 0x00, 0xE0, 0x00, 0x40, /*[215] 0xF7 divide */ + 0x60, 0xE0, 0xA0, 0xC0, /*[216] 0xF8 oslash */ + 0x80, 0x40, 0xA0, 0xA0, 0x60, /*[217] 0xF9 ugrave */ + 0x20, 0x40, 0xA0, 0xA0, 0x60, /*[218] 0xFA uacute */ + 0xE0, 0x00, 0xA0, 0xA0, 0x60, /*[219] 0xFB ucircumflex */ + 0xA0, 0x00, 0xA0, 0xA0, 0x60, /*[220] 0xFC udieresis */ + 0x20, 0x40, 0xA0, 0x60, 0x20, 0x40, /*[221] 0xFD yacute */ + 0x80, 0xC0, 0xA0, 0xC0, 0x80, /*[222] 0xFE thorn */ + 0xA0, 0x00, 0xA0, 0x60, 0x20, 0x40, /*[223] 0xFF ydieresis */ }; -// Return pointer to the 5 column bytes for a character. -// Falls back to '?' for characters outside the printable ASCII range. -inline const uint8_t* dpxFontGlyph(char c) { - uint8_t idx = (uint8_t)c; - if (idx < 0x20 || idx > 0x7E) idx = 0x3F; // '?' - return DPX_FONT[idx - 0x20]; -} +/* {offset, width, height, advance cursor, x offset, y offset} */ +const GFXglyph AwtrixFontGlyphs[] PROGMEM = { + { 0 , 8 , 1 , 2 , 0 , -5 }, /*[0] 0x20 space */ + { 1 , 8 , 5 , 2 , 0 , -5 }, /*[1] 0x21 exclam */ + { 6 , 8 , 2 , 4 , 0 , -5 }, /*[2] 0x22 quotedbl */ + { 8 , 8 , 5 , 4 , 0 , -5 }, /*[3] 0x23 numbersign */ + { 13 , 8 , 5 , 4 , 0 , -5 }, /*[4] 0x24 dollar */ + { 18 , 8 , 5 , 4 , 0 , -5 }, /*[5] 0x25 percent */ + { 23 , 8 , 5 , 4 , 0 , -5 }, /*[6] 0x26 ampersand */ + { 28 , 8 , 2 , 2 , 0 , -5 }, /*[7] 0x27 quotesingle */ + { 30 , 8 , 5 , 3 , 0 , -5 }, /*[8] 0x28 parenleft */ + { 35 , 8 , 5 , 3 , 0 , -5 }, /*[9] 0x29 parenright */ + { 40 , 8 , 3 , 4 , 0 , -5 }, /*[10] 0x2A asterisk */ + { 43 , 8 , 3 , 4 , 0 , -4 }, /*[11] 0x2B plus */ + { 46 , 8 , 2 , 3 , 0 , -1 }, /*[12] 0x2C comma */ + { 48 , 8 , 1 , 4 , 0 , -3 }, /*[13] 0x2D hyphen */ + { 49 , 8 , 1 , 2 , 0 , -1 }, /*[14] 0x2E period */ + { 50 , 8 , 5 , 4 , 0 , -5 }, /*[15] 0x2F slash */ + { 55 , 8 , 5 , 4 , 0 , -5 }, /*[16] 0x30 zero */ + { 60 , 8 , 5 , 4 , 0 , -5 }, /*[17] 0x31 one */ + { 65 , 8 , 5 , 4 , 0 , -5 }, /*[18] 0x32 two */ + { 70 , 8 , 5 , 4 , 0 , -5 }, /*[19] 0x33 three */ + { 75 , 8 , 5 , 4 , 0 , -5 }, /*[20] 0x34 four */ + { 80 , 8 , 5 , 4 , 0 , -5 }, /*[21] 0x35 five */ + { 85 , 8 , 5 , 4 , 0 , -5 }, /*[22] 0x36 six */ + { 90 , 8 , 5 , 4 , 0 , -5 }, /*[23] 0x37 seven */ + { 95 , 8 , 5 , 4 , 0 , -5 }, /*[24] 0x38 eight */ + { 100 , 8 , 5 , 4 , 0 , -5 }, /*[25] 0x39 nine */ + { 105 , 8 , 3 , 2 , 0 , -4 }, /*[26] 0x3A colon */ + { 108 , 8 , 4 , 3 , 0 , -4 }, /*[27] 0x3B semicolon */ + { 112 , 8 , 5 , 4 , 0 , -5 }, /*[28] 0x3C less */ + { 117 , 8 , 3 , 4 , 0 , -4 }, /*[29] 0x3D equal */ + { 120 , 8 , 5 , 4 , 0 , -5 }, /*[30] 0x3E greater */ + { 125 , 8 , 5 , 4 , 0 , -5 }, /*[31] 0x3F question */ + { 130 , 8 , 5 , 4 , 0 , -5 }, /*[32] 0x40 at */ + { 135 , 8 , 5 , 4 , 0 , -5 }, /*[33] 0x41 A */ + { 140 , 8 , 5 , 4 , 0 , -5 }, /*[34] 0x42 B */ + { 145 , 8 , 5 , 4 , 0 , -5 }, /*[35] 0x43 C */ + { 150 , 8 , 5 , 4 , 0 , -5 }, /*[36] 0x44 D */ + { 155 , 8 , 5 , 4 , 0 , -5 }, /*[37] 0x45 E */ + { 160 , 8 , 5 , 4 , 0 , -5 }, /*[38] 0x46 F */ + { 165 , 8 , 5 , 4 , 0 , -5 }, /*[39] 0x47 G */ + { 170 , 8 , 5 , 4 , 0 , -5 }, /*[40] 0x48 H */ + { 175 , 8 , 5 , 2 , 0 , -5 }, /*[41] 0x49 I */ + { 180 , 8 , 5 , 4 , 0 , -5 }, /*[42] 0x4A J */ + { 185 , 8 , 5 , 4 , 0 , -5 }, /*[43] 0x4B K */ + { 190 , 8 , 5 , 4 , 0 , -5 }, /*[44] 0x4C L */ + { 195 , 8 , 5 , 6 , 0 , -5 }, /*[45] 0x4D M */ + { 200 , 8 , 5 , 5 , 0 , -5 }, /*[46] 0x4E N */ + { 205 , 8 , 5 , 4 , 0 , -5 }, /*[47] 0x4F O */ + { 210 , 8 , 5 , 4 , 0 , -5 }, /*[48] 0x50 P */ + { 215 , 8 , 5 , 5 , 0 , -5 }, /*[49] 0x51 Q */ + { 220 , 8 , 5 , 4 , 0 , -5 }, /*[50] 0x52 R */ + { 225 , 8 , 5 , 4 , 0 , -5 }, /*[51] 0x53 S */ + { 230 , 8 , 5 , 4 , 0 , -5 }, /*[52] 0x54 T */ + { 235 , 8 , 5 , 4 , 0 , -5 }, /*[53] 0x55 U */ + { 240 , 8 , 5 , 4 , 0 , -5 }, /*[54] 0x56 V */ + { 245 , 8 , 5 , 6 , 0 , -5 }, /*[55] 0x57 W */ + { 250 , 8 , 5 , 4 , 0 , -5 }, /*[56] 0x58 X */ + { 255 , 8 , 5 , 4 , 0 , -5 }, /*[57] 0x59 Y */ + { 260 , 8 , 5 , 4 , 0 , -5 }, /*[58] 0x5A Z */ + { 265 , 8 , 5 , 4 , 0 , -5 }, /*[59] 0x5B bracketleft */ + { 270 , 8 , 3 , 4 , 0 , -4 }, /*[60] 0x5C backslash */ + { 273 , 8 , 5 , 4 , 0 , -5 }, /*[61] 0x5D bracketright */ + { 278 , 8 , 2 , 4 , 0 , -5 }, /*[62] 0x5E asciicircum */ + { 280 , 8 , 1 , 4 , 0 , -1 }, /*[63] 0x5F underscore */ + { 281 , 8 , 2 , 3 , 0 , -5 }, /*[64] 0x60 grave */ + { 283 , 8 , 4 , 4 , 0 , -4 }, /*[65] 0x61 a */ + { 287 , 8 , 5 , 4 , 0 , -5 }, /*[66] 0x62 b */ + { 292 , 8 , 4 , 4 , 0 , -4 }, /*[67] 0x63 c */ + { 296 , 8 , 5 , 4 , 0 , -5 }, /*[68] 0x64 d */ + { 301 , 8 , 4 , 4 , 0 , -4 }, /*[69] 0x65 e */ + { 305 , 8 , 5 , 4 , 0 , -5 }, /*[70] 0x66 f */ + { 310 , 8 , 5 , 4 , 0 , -4 }, /*[71] 0x67 g */ + { 315 , 8 , 5 , 4 , 0 , -5 }, /*[72] 0x68 h */ + { 320 , 8 , 5 , 2 , 0 , -5 }, /*[73] 0x69 i */ + { 325 , 8 , 6 , 4 , 0 , -5 }, /*[74] 0x6A j */ + { 331 , 8 , 5 , 4 , 0 , -5 }, /*[75] 0x6B k */ + { 336 , 8 , 5 , 4 , 0 , -5 }, /*[76] 0x6C l */ + { 341 , 8 , 4 , 4 , 0 , -4 }, /*[77] 0x6D m */ + { 345 , 8 , 4 , 4 , 0 , -4 }, /*[78] 0x6E n */ + { 349 , 8 , 4 , 4 , 0 , -4 }, /*[79] 0x6F o */ + { 353 , 8 , 5 , 4 , 0 , -4 }, /*[80] 0x70 p */ + { 358 , 8 , 5 , 4 , 0 , -4 }, /*[81] 0x71 q */ + { 363 , 8 , 4 , 4 , 0 , -4 }, /*[82] 0x72 r */ + { 367 , 8 , 4 , 4 , 0 , -4 }, /*[83] 0x73 s */ + { 371 , 8 , 5 , 4 , 0 , -5 }, /*[84] 0x74 t */ + { 376 , 8 , 4 , 4 , 0 , -4 }, /*[85] 0x75 u */ + { 380 , 8 , 4 , 4 , 0 , -4 }, /*[86] 0x76 v */ + { 384 , 8 , 4 , 4 , 0 , -4 }, /*[87] 0x77 w */ + { 388 , 8 , 4 , 4 , 0 , -4 }, /*[88] 0x78 x */ + { 392 , 8 , 5 , 4 , 0 , -4 }, /*[89] 0x79 y */ + { 397 , 8 , 4 , 4 , 0 , -4 }, /*[90] 0x7A z */ + { 401 , 8 , 5 , 4 , 0 , -5 }, /*[91] 0x7B braceleft */ + { 406 , 8 , 5 , 2 , 0 , -5 }, /*[92] 0x7C bar */ + { 411 , 8 , 5 , 4 , 0 , -5 }, /*[93] 0x7D braceright */ + { 416 , 8 , 2 , 4 , 0 , -5 }, /*[94] 0x7E asciitilde */ + + {418 , 8 , 5 , 4 , 0 , -5 }, /*[95] 0x7F А */ + {423 , 8 , 5 , 4 , 0 , -5 }, /*[96] 0x80 Б */ + {428 , 8 , 5 , 4 , 0 , -5 }, /*[97] 0x81 В */ + {433 , 8 , 5 , 4 , 0 , -5 }, /*[98] 0x82 Г */ + {438 , 8 , 5 , 6 , 0 , -5 }, /*[99] 0x83 Д */ + {443 , 8 , 5 , 4 , 0 , -5 }, /*[100] 0x84 Е */ + {448 , 8 , 5 , 6 , 0 , -5 }, /*[101] 0x85 Ж */ + {453 , 8 , 5 , 4 , 0 , -5 }, /*[102] 0x86 З */ + {458 , 8 , 5 , 5 , 0 , -5 }, /*[103] 0x87 И */ + {463 , 8 , 5 , 5 , 0 , -5 }, /*[104] 0x88 Й */ + {468 , 8 , 5 , 4 , 0 , -5 }, /*[105] 0x89 К */ + {473 , 8 , 5 , 4 , 0 , -5 }, /*[106] 0x8A Л */ + {478 , 8 , 5 , 6 , 0 , -5 }, /*[107] 0x8B М */ + {483 , 8 , 5 , 4 , 0 , -5 }, /*[108] 0x8C Н */ + {488 , 8 , 5 , 4 , 0 , -5 }, /*[109] 0x8D О */ + {493 , 8 , 5 , 4 , 0 , -5 }, /*[110] 0x8E П */ + {498 , 8 , 5 , 4 , 0 , -5 }, /*[111] 0x8F Р */ + {503 , 8 , 5 , 4 , 0 , -5 }, /*[112] 0x90 С */ + {508 , 8 , 5 , 4 , 0 , -5 }, /*[113] 0x91 Т */ + {513 , 8 , 5 , 4 , 0 , -5 }, /*[114] 0x92 У */ + {518 , 8 , 5 , 6 , 0 , -5 }, /*[115] 0x93 Ф */ + {523 , 8 , 5 , 4 , 0 , -5 }, /*[116] 0x94 Х */ + {528 , 8 , 5 , 5 , 0 , -5 }, /*[117] 0x95 Ц */ + {533 , 8 , 5 , 4 , 0 , -5 }, /*[118] 0x96 Ч */ + {538 , 8 , 5 , 6 , 0 , -5 }, /*[119] 0x97 Ш */ + {543 , 8 , 5 , 7 , 0 , -5 }, /*[120] 0x98 Щ */ + {548 , 8 , 5 , 5 , 0 , -5 }, /*[121] 0x99 Ъ */ + {553 , 8 , 5 , 6 , 0 , -5 }, /*[122] 0x9A Ы */ + {558 , 8 , 5 , 4 , 0 , -5 }, /*[123] 0x9B Ь */ + {563 , 8 , 5 , 4 , 0 , -5 }, /*[124] 0x9C Э */ + {568 , 8 , 5 , 6 , 0 , -5 }, /*[125] 0x9D Ю */ + {573 , 8 , 5 , 4 , 0 , -5 }, /*[126] 0x9E Я */ + {578 , 8 , 7 , 4 , 0 , -5 }, /*[127] 0x9F Ґ */ + {585 , 8 , 5 , 4 , 0 , -5 }, /*[128] 0xA0 Є */ + + {590 , 8 , 5 , 2 , 0 , -5 } , /*[129] 0xA1 exclamdown */ + {595 , 8 , 5 , 4 , 0 , -5 } , /*[130] 0xA2 cent */ + {600 , 8 , 5 , 4 , 0 , -5 } , /*[131] 0xA3 sterling */ + {605 , 8 , 5 , 4 , 0 , -5 } , /*[132] 0xA4 currency */ + {610 , 8 , 5 , 4 , 0 , -5 } , /*[133] 0xA5 yen */ + {615 , 8 , 5 , 2 , 0 , -5 } , /*[134] 0xA6 brokenbar */ + {620 , 8 , 5 , 4 , 0 , -5 } , /*[135] 0xA7 section */ + {625 , 8 , 1 , 4 , 0 , -5 } , /*[136] 0xA8 dieresis */ + {626 , 8 , 3 , 4 , 0 , -5 } , /*[137] 0xA9 copyright */ + {629 , 8 , 5 , 4 , 0 , -5 } , /*[138] 0xAA ordfeminine */ + {634 , 8 , 3 , 3 , 0 , -5 } , /*[139] 0xAB guillemotleft */ + {637 , 8 , 2 , 4 , 0 , -4 } , /*[140] 0xAC logicalnot */ + {639 , 8 , 1 , 3 , 0 , -3 } , /*[141] 0xAD softhyphen */ + {640 , 8 , 3 , 4 , 0 , -5 } , /*[142] 0xAE registered */ + {643 , 8 , 1 , 4 , 0 , -5 } , /*[143] 0xAF macron */ + {644 , 8 , 3 , 3 , 0 , -5 } , /*[144] 0xB0 degree */ + {647 , 8 , 5 , 4 , 0 , -5 } , /*[145] 0xB1 plusminus */ + {652 , 8 , 3 , 4 , 0 , -5 } , /*[146] 0xB2 twosuperior */ + {655 , 8 , 3 , 4 , 0 , -5 } , /*[147] 0xB3 threesuperior */ + {658 , 8 , 2 , 3 , 0 , -5 } , /*[148] 0xB4 acute */ + {660 , 8 , 5 , 4 , 0 , -5 } , /*[149] 0xB5 mu */ + {665 , 8 , 5 , 4 , 0 , -5 } , /*[150] 0xB6 paragraph */ + {670 , 8 , 3 , 4 , 0 , -4 } , /*[151] 0xB7 periodcentered */ + {673 , 8 , 3 , 4 , 0 , -3 } , /*[152] 0xB8 cedilla */ + {676 , 8 , 3 , 2 , 0 , -5 } , /*[153] 0xB9 onesuperior */ + {679 , 8 , 5 , 4 , 0 , -5 } , /*[154] 0xBA ordmasculine */ + {684 , 8 , 3 , 3 , 0 , -5 } , /*[155] 0xBB guillemotright */ + {687 , 8 , 5 , 4 , 0 , -5 } , /*[156] 0xBC onequarter */ + {692 , 8 , 5 , 4 , 0 , -5 } , /*[157] 0xBD onehalf */ + {697 , 8 , 5 , 4 , 0 , -5 } , /*[158] 0xBE threequarters */ + {702 , 8 , 5 , 4 , 0 , -5 } , /*[159] 0xBF questiondown */ + {707 , 8 , 5 , 4 , 0 , -5 } , /*[160] 0xC0 Agrave */ + {712 , 8 , 5 , 4 , 0 , -5 } , /*[161] 0xC1 Aacute */ + {717 , 8 , 5 , 4 , 0 , -5 } , /*[162] 0xC2 Acircumflex */ + {722 , 8 , 5 , 4 , 0 , -5 } , /*[163] 0xC3 Atilde */ + {727 , 8 , 5 , 4 , 0 , -5 } , /*[164] 0xC4 Adieresis */ + {732 , 8 , 5 , 4 , 0 , -5 } , /*[165] 0xC5 Aring */ + {737 , 8 , 5 , 4 , 0 , -5 } , /*[166] 0xC6 AE */ + {742 , 8 , 6 , 4 , 0 , -5 } , /*[167] 0xC7 Ccedilla */ + {748 , 8 , 5 , 4 , 0 , -5 } , /*[168] 0xC8 Egrave */ + {753 , 8 , 5 , 4 , 0 , -5 } , /*[169] 0xC9 Eacute */ + {758 , 8 , 5 , 4 , 0 , -5 } , /*[170] 0xCA Ecircumflex */ + {763 , 8 , 5 , 4 , 0 , -5 } , /*[171] 0xCB Edieresis */ + {768 , 8 , 5 , 4 , 0 , -5 } , /*[172] 0xCC Igrave */ + {773 , 8 , 5 , 4 , 0 , -5 } , /*[173] 0xCD Iacute */ + {778 , 8 , 5 , 4 , 0 , -5 } , /*[174] 0xCE Icircumflex */ + {783 , 8 , 5 , 4 , 0 , -5 } , /*[175] 0xCF Idieresis */ + {788 , 8 , 5 , 4 , 0 , -5 } , /*[176] 0xD0 Eth */ + {793 , 8 , 5 , 4 , 0 , -5 } , /*[177] 0xD1 Ntilde */ + {798 , 8 , 5 , 4 , 0 , -5 } , /*[178] 0xD2 Ograve */ + {803 , 8 , 5 , 4 , 0 , -5 } , /*[179] 0xD3 Oacute */ + {808 , 8 , 5 , 4 , 0 , -5 } , /*[180] 0xD4 Ocircumflex */ + {813 , 8 , 5 , 4 , 0 , -5 } , /*[181] 0xD5 Otilde */ + {818 , 8 , 5 , 4 , 0 , -5 } , /*[182] 0xD6 Odieresis */ + {823 , 8 , 3 , 4 , 0 , -4 } , /*[183] 0xD7 multiply */ + {826 , 8 , 5 , 4 , 0 , -5 } , /*[184] 0xD8 Oslash */ + {831 , 8 , 5 , 4 , 0 , -5 } , /*[185] 0xD9 Ugrave */ + {836 , 8 , 5 , 4 , 0 , -5 } , /*[186] 0xDA Uacute */ + {841 , 8 , 5 , 4 , 0 , -5 } , /*[187] 0xDB Ucircumflex */ + {846 , 8 , 5 , 4 , 0 , -5 } , /*[188] 0xDC Udieresis */ + {851 , 8 , 5 , 4 , 0 , -5 } , /*[189] 0xDD Yacute */ + {856 , 8 , 5 , 4 , 0 , -5 } , /*[190] 0xDE Thorn */ + {861 , 8 , 6 , 4 , 0 , -5 } , /*[191] 0xDF germandbls */ + {867 , 8 , 5 , 4 , 0 , -5 } , /*[192] 0xE0 agrave */ + {872 , 8 , 5 , 4 , 0 , -5 } , /*[193] 0xE1 aacute */ + {877 , 8 , 5 , 4 , 0 , -5 } , /*[194] 0xE2 acircumflex */ + {882 , 8 , 5 , 4 , 0 , -5 } , /*[195] 0xE3 atilde */ + {887 , 8 , 5 , 4 , 0 , -5 } , /*[196] 0xE4 adieresis */ + {892 , 8 , 5 , 4 , 0 , -5 } , /*[197] 0xE5 aring */ + {897 , 8 , 4 , 4 , 0 , -4 } , /*[198] 0xE6 ae */ + {901 , 8 , 5 , 4 , 0 , -4 } , /*[199] 0xE7 copy&pasteistrash */ + {906 , 8 , 5 , 4 , 0 , -5 } , /*[200] 0xE8 egrave */ + {911 , 8 , 5 , 4 , 0 , -5 } , /*[201] 0xE9 eacute */ + {916 , 8 , 5 , 4 , 0 , -5 } , /*[202] 0xEA ecircumflex */ + {921 , 8 , 5 , 4 , 0 , -5 } , /*[203] 0xEB edieresis */ + {926 , 8 , 5 , 3 , 0 , -5 } , /*[204] 0xEC igrave */ + {931 , 8 , 5 , 3 , 0 , -5 } , /*[205] 0xED iacute */ + {936 , 8 , 5 , 4 , 0 , -5 } , /*[206] 0xEE fckpixelit */ + {941 , 8 , 5 , 4 , 0 , -5 } , /*[207] 0xEF idieresis */ + {946 , 8 , 5 , 4 , 0 , -5 } , /*[208] 0xF0 eth */ + {951 , 8 , 5 , 4 , 0 , -5 } , /*[209] 0xF1 ntilde */ + {956 , 8 , 5 , 4 , 0 , -5 } , /*[210] 0xF2 ograve */ + {961 , 8 , 5 , 4 , 0 , -5 } , /*[211] 0xF3 oacute */ + {966 , 8 , 5 , 4 , 0 , -5 } , /*[212] 0xF4 ocircumflex */ + {971 , 8 , 5 , 4 , 0 , -5 } , /*[213] 0xF5 otilde */ + {976 , 8 , 5 , 4 , 0 , -5 } , /*[214] 0xF6 odieresis */ + {981 , 8 , 5 , 4 , 0 , -5 } , /*[215] 0xF7 divide */ + {986 , 8 , 4 , 4 , 0 , -4 } , /*[216] 0xF8 oslash */ + {990 , 8 , 5 , 4 , 0 , -5 } , /*[217] 0xF9 ugrave */ + {995 , 8 , 5 , 4 , 0 , -5 } , /*[218] 0xFA uacute */ + {1000 , 8 , 5 , 4 , 0 , -5 }, /*[219] 0xFB ucircumflex */ + {1005 , 8 , 5 , 4 , 0 , -5 }, /*[220] 0xFC udieresis */ + {1010 , 8 , 6 , 4 , 0 , -5 }, /*[221] 0xFD yacute */ + {1016 , 8 , 5 , 4 , 0 , -4 }, /*[222] 0xFE thorn */ + {1021 , 8 , 6 , 4 , 0 , -5 }, /*[223] 0xFF ydieresis */ +}; + +const GFXfont AwtrixFont PROGMEM = { + (uint8_t *)AwtrixBitmaps, + (GFXglyph *)AwtrixFontGlyphs, + 0x20, 0xFF, 6}; -// Pixel width of a string (includes inter-character gap, no trailing gap). -inline int dpxTextPixelWidth(const char* str) { - if (!str || *str == '\0') return 0; - int len = strlen(str); - return len * (DPX_FONT_W + DPX_FONT_GAP) - DPX_FONT_GAP; +// ── Pixel-width helper (defined after font data so AwtrixFont is in scope) ───── +// Returns the total pixel width of a null-terminated string. +static int dpxTextPixelWidth(const char* str) { + if (!str) return 0; + int w = 0; + while (*str) { + uint8_t c = (uint8_t)*str++; + if (c < AwtrixFont.first || c > AwtrixFont.last) continue; + GFXglyph glyph; + memcpy_P(&glyph, &AwtrixFont.glyph[c - AwtrixFont.first], sizeof(GFXglyph)); + w += glyph.xAdvance; + } + // Trim trailing 1-px gap of last character + if (w > 0) w--; + return w; } diff --git a/usermods/dpx_matrix/dpx_matrix.cpp b/usermods/dpx_matrix/dpx_matrix.cpp index 5651307ed4..efa1576e61 100644 --- a/usermods/dpx_matrix/dpx_matrix.cpp +++ b/usermods/dpx_matrix/dpx_matrix.cpp @@ -15,3 +15,11 @@ #include "wled.h" #include "dpx_matrix.h" + +// ── Global definitions ──────────────────────────────────────────────────────── +// dpxIndicator is declared extern in dpx_osc.h; one definition here. +uint32_t dpxIndicator[3] = {0, 0, 0}; + +// ── Usermod registration ────────────────────────────────────────────────────── +static DpxMatrix dpxMatrixMod; +REGISTER_USERMOD(dpxMatrixMod); diff --git a/usermods/dpx_matrix/dpx_matrix.h b/usermods/dpx_matrix/dpx_matrix.h index 111ce9a80a..ea258b3f09 100644 --- a/usermods/dpx_matrix/dpx_matrix.h +++ b/usermods/dpx_matrix/dpx_matrix.h @@ -25,6 +25,8 @@ #pragma once // Include all module headers in dependency order +#include "dpx_firstboot.h" +#include "dpx_buzzer.h" #include "dpx_font.h" #include "dpx_text.h" #include "dpx_persist.h" @@ -32,12 +34,39 @@ #include "dpx_notifications.h" #include "dpx_tc.h" #include "dpx_osc.h" +#include "dpx_overlay.h" +#include "dpx_mqtt.h" #include "dpx_api.h" class DpxMatrix : public Usermod { private: - bool _initDone = false; + bool _initDone = false; + + // ── Button debounce state ─────────────────────────────────────────────── + // Buttons are active-LOW (internal pull-up). We fire on falling edge. + struct BtnState { + uint8_t pin; + bool lastRaw = true; // last raw read (true = not pressed) + bool debounced = true; // debounced state + uint32_t lastMs = 0; + }; + BtnState _btn[3]; // index 0=left, 1=mid, 2=right + + // Poll one button; returns true on falling-edge (press event). + bool _pollBtn(BtnState& b) { + if (b.pin == 255) return false; + bool raw = digitalRead(b.pin); + uint32_t now = millis(); + if (raw != b.lastRaw) b.lastMs = now; // reset timer on any change + b.lastRaw = raw; + if ((now - b.lastMs) >= 50) { // 50 ms debounce + bool prev = b.debounced; + b.debounced = raw; + if (prev && !raw) return true; // falling edge = press + } + return false; + } // Render the 3 indicator pixels (corner dots). // Indicator 1 = top-left (pixel 0) @@ -53,6 +82,10 @@ class DpxMatrix : public Usermod { static const char _name[]; void setup() override { + // Write default cfg.json on first boot if LittleFS has none. + // Must run before dpxLoadDev() so WLED picks it up on next reboot. + dpxFirstBoot(); + // Load persistent settings dpxLoadDev(); dpxLoadOscListeners(); @@ -61,8 +94,21 @@ class DpxMatrix : public Usermod { dpxRebuildLoop(); dpxAppStartMs = millis(); - // Start UDP for OSC - dpxOscBegin(); + // Initialise button pins (active-low, internal pull-up) + const uint8_t btnPins[3] = { DPX_BTN_LEFT, DPX_BTN_MID, DPX_BTN_RIGHT }; + for (int i = 0; i < 3; i++) { + _btn[i].pin = btnPins[i]; + _btn[i].lastRaw = true; + _btn[i].debounced = true; + _btn[i].lastMs = 0; + if (_btn[i].pin != 255) pinMode(_btn[i].pin, INPUT_PULLUP); + } + + // Initialise TC001 buzzer pin; drives LOW to prevent float noise. + dpxBuzzerInit(); + + // NOTE: dpxOscBegin() is called in connected() once WiFi is up. + // Opening a UDP socket before lwip is ready crashes the device. // Register HTTP routes dpxRegisterRoutes(); @@ -71,9 +117,64 @@ class DpxMatrix : public Usermod { DEBUG_PRINTLN(F("DpxMatrix: setup complete")); } + void connected() override { + // Safe to open UDP socket now that WiFi/lwip is ready + dpxOscBegin(); + + // Re-apply POSIX timezone AFTER WLED's configTime() call (which runs on + // WiFi connect and overwrites TZ with a dumb UTC-offset string). + // configTzTime sets TZ env + kicks off an NTP sync in one shot. + if (DPX_TIMEZONE.length()) { + configTzTime(DPX_TIMEZONE.c_str(), ntpServerName); + DEBUG_PRINTF("DpxMatrix: TZ applied: %s\n", DPX_TIMEZONE.c_str()); + } + + DEBUG_PRINTLN(F("DpxMatrix: WiFi connected, OSC UDP started")); + + // Print IP prominently — visible any time serial monitor is open + String ip = WiFi.localIP().toString(); + Serial.println(); + Serial.println(F("┌─────────────────────────────┐")); + Serial.print (F("│ dpx_tc002 IP: ")); + Serial.print (ip); + Serial.println(F(" │")); + Serial.println(F("└─────────────────────────────┘")); + Serial.println(); + Serial.printf("[dpx] IP: %s\n", ip.c_str()); + StaticJsonDocument<128> doc; + doc["text"] = ip; + doc["color"] = "#00FF88"; + doc["repeat"] = 1; + String s; serializeJson(doc, s); + dpxPushNotification(s.c_str()); + } + void loop() override { if (!_initDone) return; + // Rate-limit to ~50Hz max. Constant UDP/timer polling on every Arduino + // loop tick (which runs at 300-1000Hz) hammers the lwip socket layer + // and slows down HTTP/WebSocket responses. + static unsigned long _lastLoopMs = 0; + unsigned long now = millis(); + if (now - _lastLoopMs < 20) return; + _lastLoopMs = now; + + // Reprint IP whenever serial is freshly connected + static bool _serialWasConnected = false; + bool serialNow = (bool)Serial; + if (serialNow && !_serialWasConnected && WiFi.localIP()[0] != 0) { + String ip = WiFi.localIP().toString(); + Serial.println(); + Serial.println(F("┌─────────────────────────────┐")); + Serial.print (F("│ dpx_tc002 IP: ")); + Serial.print (ip); + Serial.println(F(" │")); + Serial.println(F("└─────────────────────────────┘")); + Serial.println(); + } + _serialWasConnected = serialNow; + // Advance app pointer when duration expires dpxAppLoopTick(); @@ -82,10 +183,22 @@ class DpxMatrix : public Usermod { // Receive OSC packets dpxOscTick(); + + // Advance RTTTL note sequencer + dpxBuzzerTick(); + + // Physical buttons + // LEFT → previous app, RIGHT → next app, MIDDLE → toggle dpxEnabled + if (_pollBtn(_btn[0])) dpxPrevApp(); + if (_pollBtn(_btn[2])) dpxNextApp(); + if (_pollBtn(_btn[1])) { + dpxEnabled = !dpxEnabled; + DEBUG_PRINTF("DpxMatrix: button toggle enabled=%d\n", (int)dpxEnabled); + } } void handleOverlayDraw() override { - if (!_initDone) return; + if (!_initDone || !dpxEnabled) return; // Notifications take priority over the app loop if (dpxNotifTick()) { @@ -94,10 +207,100 @@ class DpxMatrix : public Usermod { dpxRenderCurrentApp(); } - // Overlay indicator dots on top of everything + // Pixel effects + text overlay on top of app content + dpxRenderOverlays(); + + // Indicator corner dots (topmost layer) renderIndicators(); } + // ── MQTT integration ────────────────────────────────────────────────── + void onMqttConnect(bool /*sessionPresent*/) override { + dpxMqttConnect(); + } + + bool onMqttMessage(char* topic, char* payload) override { + // dpx_mqtt.h handles dpx/* and {deviceTopic}/dpx/* topics + if (dpxMqttMessage(topic, payload)) return true; + return false; + } + + // ── JSON state integration (POST /json {"dpx":{...}}) ───────────────── + void readFromJsonState(JsonObject& obj) override { + JsonObject dpx = obj[F("dpx")]; + if (dpx.isNull()) return; + + // Notifications + if (dpx.containsKey(F("notify"))) { + String s; serializeJson(dpx[F("notify")], s); + dpxPushNotification(s.c_str()); + } + if (dpx.containsKey(F("notify_dismiss"))) dpxDismissNotification(); + + // Timecode + if (dpx.containsKey(F("tc"))) { + String tc = dpx[F("tc")].as(); tc.trim(); + if (tc.length() >= 8) dpxPushTC(tc); + } + + // Enable/disable matrix overlay + if (dpx.containsKey(F("enabled"))) dpxEnabled = dpx[F("enabled")].as(); + + // App loop control + if (dpx.containsKey(F("nextapp"))) dpxNextApp(); + if (dpx.containsKey(F("previousapp"))) dpxPrevApp(); + if (dpx.containsKey(F("switch"))) { + String s; serializeJson(dpx[F("switch")], s); + dpxSwitchToApp(s.c_str()); + } + + // Custom app upsert: {"app":{"name":{...}}} + if (dpx.containsKey(F("app"))) { + JsonObject apps = dpx[F("app")].as(); + for (JsonPair kv : apps) { + String v; serializeJson(kv.value(), v); + dpxSetCustomApp(String(kv.key().c_str()), v.c_str()); + } + } + + // Text overlay + if (dpx.containsKey(F("overlay"))) { + String s; serializeJson(dpx[F("overlay")], s); + dpxSetOverlay(s.c_str()); + } + + // Pixel effect + if (dpx.containsKey(F("effect"))) { + String s; serializeJson(dpx[F("effect")], s); + dpxSetPixelEffect(s.c_str()); + } + + // Indicators + for (int i = 1; i <= 3; i++) { + String key = String(F("indicator")) + i; + if (dpx.containsKey(key)) { + JsonArray a = dpx[key].as(); + if (a.size() >= 3) + dpxIndicator[i-1] = ((uint32_t)(uint8_t)a[0] << 16) + | ((uint32_t)(uint8_t)a[1] << 8) + | (uint32_t)(uint8_t)a[2]; + else + dpxIndicator[i-1] = 0; + } + } + } + + void addToJsonState(JsonObject& obj) override { + JsonObject dpx = obj.createNestedObject(F("dpx")); + dpx[F("enabled")] = dpxEnabled; + dpx[F("app")] = (dpxCurrentApp < dpxApps.size()) + ? dpxApps[dpxCurrentApp].name : String(); + dpx[F("notif")] = (int)dpxNotifQueue.size(); + dpx[F("autoTrans")] = dpxAutoTrans; + dpx[F("overlay")] = dpxTextOverlay.active ? dpxTextOverlay.text : String(); + dpx[F("effect")] = dpxPixelEffect.active ? dpxPixelEffect.name : String(); + } + uint16_t getId() override { return USERMOD_ID_DPX_MATRIX; } void addToJsonInfo(JsonObject& root) override { @@ -108,17 +311,19 @@ class DpxMatrix : public Usermod { // ── Usermod settings persist (WLED /cfg.json) ───────────────────────── void addToConfig(JsonObject& root) override { JsonObject top = root.createNestedObject(FPSTR(_name)); - top["atime"] = DPX_ATIME; - top["atrans"] = DPX_ATRANS; - top["sspeed"] = DPX_SSPEED; + top["enabled"] = dpxEnabled; + top["atime"] = DPX_ATIME; + top["atrans"] = DPX_ATRANS; + top["sspeed"] = DPX_SSPEED; } bool readFromConfig(JsonObject& root) override { JsonObject top = root[FPSTR(_name)]; if (top.isNull()) return false; - if (top.containsKey("atime")) DPX_ATIME = top["atime"]; - if (top.containsKey("atrans")) DPX_ATRANS = top["atrans"]; - if (top.containsKey("sspeed")) DPX_SSPEED = top["sspeed"]; + if (top.containsKey("enabled")) dpxEnabled = top["enabled"].as(); + if (top.containsKey("atime")) DPX_ATIME = top["atime"]; + if (top.containsKey("atrans")) DPX_ATRANS = top["atrans"]; + if (top.containsKey("sspeed")) DPX_SSPEED = top["sspeed"]; return true; } }; diff --git a/usermods/dpx_matrix/dpx_persist.h b/usermods/dpx_matrix/dpx_persist.h index 6d25fd278b..fe5a1e6f5e 100644 --- a/usermods/dpx_matrix/dpx_persist.h +++ b/usermods/dpx_matrix/dpx_persist.h @@ -39,6 +39,8 @@ static int DPX_ATIME = 7; // app display seconds static bool DPX_ATRANS = true; // auto-advance apps static int DPX_SSPEED = 100; // global scroll speed % static bool DPX_UPPERCASE = true; // force uppercase text +static bool dpxEnabled = true; // false = pass-through to WLED effects +static String DPX_TIMEZONE; // POSIX TZ string (e.g. PST8PDT,...) // ── Load dev.json from LittleFS ─────────────────────────────────────────────── static void dpxLoadDev() { @@ -61,6 +63,11 @@ static void dpxLoadDev() { if (doc.containsKey("rotate_screen")) DPX_ROTATE_SCREEN = doc["rotate_screen"].as(); if (doc.containsKey("mirror_screen")) DPX_MIRROR_SCREEN = doc["mirror_screen"].as(); if (doc.containsKey("sensor_reading")) DPX_SENSOR_READING = doc["sensor_reading"].as(); + if (doc.containsKey("timezone_posix")) { + DPX_TIMEZONE = doc["timezone_posix"].as(); + setenv("TZ", DPX_TIMEZONE.c_str(), 1); + tzset(); + } } // ── Merge a JSON object into dev.json and apply immediately ─────────────────── @@ -92,6 +99,11 @@ static bool dpxMergeDev(const char* json) { if (incoming.containsKey("max_brightness")) DPX_MAX_BRI = incoming["max_brightness"].as(); if (incoming.containsKey("ldr_factor")) DPX_LDR_FACTOR = incoming["ldr_factor"].as(); if (incoming.containsKey("ldr_gamma")) DPX_LDR_GAMMA = incoming["ldr_gamma"].as(); + if (incoming.containsKey("timezone_posix")) { + DPX_TIMEZONE = incoming["timezone_posix"].as(); + setenv("TZ", DPX_TIMEZONE.c_str(), 1); + tzset(); + } return true; } diff --git a/usermods/dpx_matrix/dpx_text.h b/usermods/dpx_matrix/dpx_text.h index 21c3b38468..7445555127 100644 --- a/usermods/dpx_matrix/dpx_text.h +++ b/usermods/dpx_matrix/dpx_text.h @@ -22,8 +22,6 @@ static const int DPX_MATRIX_W = 32; static const int DPX_MATRIX_H = 8; // ── Raw pixel write ──────────────────────────────────────────────────────────── -// Writes one pixel to the WLED LED strip buffer. -// Clamps silently on out-of-bounds coordinates. static inline void dpxSetPixel(int x, int y, uint32_t color) { if (x < 0 || x >= DPX_MATRIX_W || y < 0 || y >= DPX_MATRIX_H) return; strip.setPixelColor(y * DPX_MATRIX_W + x, color); @@ -57,38 +55,56 @@ static inline uint32_t dpxRainbowColor(int charIdx, int totalChars) { return (uint32_t)rgb.r << 16 | (uint32_t)rgb.g << 8 | rgb.b; } -// ── Draw a single glyph at (x, y) ───────────────────────────────────────────── -// x, y = top-left corner. Returns the x position after the character (x + DPX_FONT_W + gap). -// Clips to matrix bounds. Columns with x < 0 are skipped (off-left). -static int dpxDrawChar(int x, int y, char c, uint32_t color) { - const uint8_t* glyph = dpxFontGlyph(c); - for (int col = 0; col < DPX_FONT_W; col++) { - int px = x + col; - if (px < 0) continue; - if (px >= DPX_MATRIX_W) break; - uint8_t colData = pgm_read_byte(glyph + col); - for (int row = 0; row < DPX_FONT_H; row++) { - int py = y + row; - if (colData & (1 << row)) { - dpxSetPixel(px, py, color); +// ── Draw a single glyph using AwtrixFont (GFX row-major format) ─────────────── +// x = left edge of where the glyph will land +// baseline = cursor_y (pass DPX_FONT_BASELINE to centre in 8-row display) +// Returns the next cursor X (x + xAdvance). +// Glyphs that land partially off-left are clipped pixel-by-pixel. +static int dpxDrawChar(int x, int baseline, char c, uint32_t color) { + extern const GFXfont AwtrixFont; + uint8_t ci = (uint8_t)c; + if (ci < AwtrixFont.first || ci > AwtrixFont.last) return x + 4; + + GFXglyph g; + memcpy_P(&g, &AwtrixFont.glyph[ci - AwtrixFont.first], sizeof(GFXglyph)); + + // Each row of the glyph is ceil(g.width/8) bytes; here always 1 byte (width=8) + int bytesPerRow = (g.width + 7) / 8; + int glyphTop = baseline + g.yOffset; // top pixel row on matrix + + for (int row = 0; row < (int)g.height; row++) { + int py = glyphTop + row; + if (py < 0 || py >= DPX_MATRIX_H) continue; + for (int b = 0; b < bytesPerRow; b++) { + uint8_t bits = pgm_read_byte( + &((uint8_t*)AwtrixFont.bitmap)[g.bitmapOffset + row * bytesPerRow + b]); + for (int bit = 7; bit >= 0; bit--) { + int col = (b * 8) + (7 - bit); + if (col >= (int)g.width) break; + int px = x + g.xOffset + col; + if (px < 0) continue; + if (px >= DPX_MATRIX_W) break; + if (bits & (1 << bit)) + dpxSetPixel(px, py, color); } } } - return x + DPX_FONT_W + DPX_FONT_GAP; + return x + g.xAdvance; } -// ── Render a text string at (x, y) ──────────────────────────────────────────── -// Renders left to right from (x, y). Clips at matrix edges. -// rainbow=true overrides color with per-character rainbow. +// ── Render a text string ─────────────────────────────────────────────────────── +// x = left cursor position +// baseline = cursor_y (use DPX_FONT_BASELINE for centered output) +// rainbow = true overrides color with per-character hue sweep // Returns the x position after the last character. -static int dpxRenderText(int x, int y, const char* text, uint32_t color, bool rainbow = false) { +static int dpxRenderText(int x, int baseline, const char* text, uint32_t color, bool rainbow = false) { if (!text) return x; int n = strlen(text); int curX = x; for (int i = 0; i < n; i++) { uint32_t c = rainbow ? dpxRainbowColor(i, n) : color; - curX = dpxDrawChar(curX, y, text[i], c); - if (curX >= DPX_MATRIX_W) break; // off-right edge + curX = dpxDrawChar(curX, baseline, text[i], c); + if (curX >= DPX_MATRIX_W) break; } return curX; } @@ -98,7 +114,7 @@ struct DpxScrollState { String text; uint32_t color = 0xFFFFFF; bool rainbow = false; - int y = 0; // row (0 = top) + int y = DPX_FONT_BASELINE; // baseline row (centred in 8-row display) int scrollX = DPX_MATRIX_W; // current x offset (starts at right edge) int speedMs = 50; // ms between scroll steps (lower = faster) unsigned long lastStepMs = 0; @@ -111,7 +127,7 @@ struct DpxScrollState { text = t; color = col; rainbow = rb; - y = y_; + y = (y_ == 0) ? DPX_FONT_BASELINE : y_; // default to centred baseline speedMs = max(10, (int)(50 * 100 / max(1, speedPct))); repeat = rep; repeatsDone = 0; diff --git a/wled00/const.h b/wled00/const.h index 3b435d1b5b..b9f64aeeef 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -696,7 +696,9 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #endif #endif #define DEFAULT_LED_TYPE TYPE_WS2812_RGB -#define DEFAULT_LED_COUNT 30 +#ifndef DEFAULT_LED_COUNT + #define DEFAULT_LED_COUNT 30 +#endif #define INTERFACE_UPDATE_COOLDOWN 1000 // time in ms to wait between websockets, alexa, and MQTT updates From e937c3c9f0d5695075c635ae6595558b77694965 Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 18 Jul 2026 12:07:30 -0400 Subject: [PATCH 4/9] fix: correct license headers from MIT to EUPL v1.2 across all dpx_matrix files --- readme.md | 12 +++++++++--- usermods/dpx_matrix/dpx_api.h | 2 +- usermods/dpx_matrix/dpx_apps.h | 2 +- usermods/dpx_matrix/dpx_buzzer.h | 2 +- usermods/dpx_matrix/dpx_firstboot.h | 2 +- usermods/dpx_matrix/dpx_html.h | 2 +- usermods/dpx_matrix/dpx_matrix.cpp | 2 +- usermods/dpx_matrix/dpx_matrix.h | 2 +- usermods/dpx_matrix/dpx_mqtt.h | 2 +- usermods/dpx_matrix/dpx_notifications.h | 2 +- usermods/dpx_matrix/dpx_osc.h | 2 +- usermods/dpx_matrix/dpx_overlay.h | 2 +- usermods/dpx_matrix/dpx_persist.h | 2 +- usermods/dpx_matrix/dpx_tc.h | 2 +- usermods/dpx_matrix/dpx_text.h | 2 +- 15 files changed, 23 insertions(+), 17 deletions(-) diff --git a/readme.md b/readme.md index eb055afd75..c55247e879 100644 --- a/readme.md +++ b/readme.md @@ -245,11 +245,17 @@ Don't forget to give the project a star! Thanks again! ## License -This firmware is distributed under the **EUPL v1.2** (inherited from WLED). See `LICENSE` for details. -The `dpx_matrix` usermod (original work) is additionally available under MIT. +This project is a fork of [WLED](https://github.com/wled/WLED) and is distributed under the **[EUPL v1.2](https://github.com/dubpixel/dpx_tc002_frm/blob/main/LICENSE)** (European Union Public Licence). -AwtrixFont used in dpx_font.h is BSD 3-Clause — see header for full attribution. +Key points: +- **Source must be provided** with any distribution — this GitHub repo fulfils that requirement +- Derivative works must be licensed under EUPL or a [compatible license](https://joinup.ec.europa.eu/collection/eupl/matrix-eupl-compatible-open-source-licences) (GPL, LGPL, AGPL, MPL, etc.) +- Attribution to WLED contributors is required — see [kno.wled.ge/about/contributors](https://kno.wled.ge/about/contributors/) + +The `dpx_matrix` usermod is original work by dubpixel, but as part of this compiled firmware distribution it is covered by EUPL v1.2. + +AwtrixFont (`dpx_font.h`) is BSD 3-Clause — see file header for full attribution. ## Contact diff --git a/usermods/dpx_matrix/dpx_api.h b/usermods/dpx_matrix/dpx_api.h index 8ccc1d07a7..f18fbb9f1f 100644 --- a/usermods/dpx_matrix/dpx_api.h +++ b/usermods/dpx_matrix/dpx_api.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_api.h — HTTP Routes: pages + REST API // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_apps.h b/usermods/dpx_matrix/dpx_apps.h index d035d93b58..825df8d307 100644 --- a/usermods/dpx_matrix/dpx_apps.h +++ b/usermods/dpx_matrix/dpx_apps.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_apps.h — App Loop System // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // NOT derived from MatrixDisplayUi.cpp (AWTRIX CC BY-NC-SA 4.0). // Written from scratch using SPEC.md §3-4 as behavioral reference. // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_buzzer.h b/usermods/dpx_matrix/dpx_buzzer.h index 04643705c8..26d65882c8 100644 --- a/usermods/dpx_matrix/dpx_buzzer.h +++ b/usermods/dpx_matrix/dpx_buzzer.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_buzzer.h — Non-blocking RTTTL tone player for TC001 (GPIO 15) // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_firstboot.h b/usermods/dpx_matrix/dpx_firstboot.h index 32bce04616..aea4503544 100644 --- a/usermods/dpx_matrix/dpx_firstboot.h +++ b/usermods/dpx_matrix/dpx_firstboot.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_firstboot.h — First-Boot Config Injection // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_html.h b/usermods/dpx_matrix/dpx_html.h index 95d775890d..6b32a9c04a 100644 --- a/usermods/dpx_matrix/dpx_html.h +++ b/usermods/dpx_matrix/dpx_html.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_html.h — PROGMEM Web UI Pages // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // Pages: /api-ref, /browse, /ctrl, /screen, /fullscreen // Ported from dpx_tc001/src/htmls.h (original work, not AWTRIX-derived). // EXCLUDED: custom_html, screen_html, backup_html (contain AWTRIX references). diff --git a/usermods/dpx_matrix/dpx_matrix.cpp b/usermods/dpx_matrix/dpx_matrix.cpp index efa1576e61..d480234eb8 100644 --- a/usermods/dpx_matrix/dpx_matrix.cpp +++ b/usermods/dpx_matrix/dpx_matrix.cpp @@ -1,7 +1,7 @@ // ================================================================================ // dpx_matrix.cpp — Usermod Entry Point // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_matrix.h b/usermods/dpx_matrix/dpx_matrix.h index ea258b3f09..b502772545 100644 --- a/usermods/dpx_matrix/dpx_matrix.h +++ b/usermods/dpx_matrix/dpx_matrix.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_matrix.h — Main Usermod Class // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_mqtt.h b/usermods/dpx_matrix/dpx_mqtt.h index 73c08be322..dbc3a710cb 100644 --- a/usermods/dpx_matrix/dpx_mqtt.h +++ b/usermods/dpx_matrix/dpx_mqtt.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_mqtt.h — MQTT Integration // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_notifications.h b/usermods/dpx_matrix/dpx_notifications.h index 85ce34625e..63d1b5b62f 100644 --- a/usermods/dpx_matrix/dpx_notifications.h +++ b/usermods/dpx_matrix/dpx_notifications.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_notifications.h — Notification Queue // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_osc.h b/usermods/dpx_matrix/dpx_osc.h index b8e1591982..0d14e349fd 100644 --- a/usermods/dpx_matrix/dpx_osc.h +++ b/usermods/dpx_matrix/dpx_osc.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_osc.h — OSC Receiver (UDP port 4210) // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // Ported/adapted from dpx_tc001 ServerManager.cpp::handleOSC() // (original work — OSC protocol handling, not AWTRIX-derived) // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_overlay.h b/usermods/dpx_matrix/dpx_overlay.h index d4437a6d92..2e1bf76457 100644 --- a/usermods/dpx_matrix/dpx_overlay.h +++ b/usermods/dpx_matrix/dpx_overlay.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_overlay.h — Text Overlay + Pixel Effects (run on top of app content) // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_persist.h b/usermods/dpx_matrix/dpx_persist.h index fe5a1e6f5e..298160c081 100644 --- a/usermods/dpx_matrix/dpx_persist.h +++ b/usermods/dpx_matrix/dpx_persist.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_persist.h — Persistent Settings (dev.json) + Runtime Globals // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_tc.h b/usermods/dpx_matrix/dpx_tc.h index ce843b444f..272452ee50 100644 --- a/usermods/dpx_matrix/dpx_tc.h +++ b/usermods/dpx_matrix/dpx_tc.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_tc.h — Timecode Display Helper // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // Ported/adapted from dpx_tc001 ServerManager.cpp::pushTCDisplay() // (original work, not AWTRIX-derived) // ================================================================================ diff --git a/usermods/dpx_matrix/dpx_text.h b/usermods/dpx_matrix/dpx_text.h index 7445555127..9ea1bd471c 100644 --- a/usermods/dpx_matrix/dpx_text.h +++ b/usermods/dpx_matrix/dpx_text.h @@ -1,7 +1,7 @@ // ================================================================================ // dpx_text.h — Text Rendering for 32×8 LED Matrix // ================================================================================ -// Original work — dubpixel / dpx_tc002 (MIT) +// Original work — dubpixel / dpx_tc002 (EUPL v1.2) // ================================================================================ // PROJECT: dpx_tc002_frm // ================================================================================ From b1d724d6a988b97ad517ffd32eb518eaace52f6e Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 18 Jul 2026 13:43:29 -0400 Subject: [PATCH 5/9] feat: app mute/remove/WLED-passthrough; button fix; time via localTime; serial debug; roadmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Any app (incl. native Time/Date/WLED) removable from rotation via dpxHiddenApps set - WLED native app: silent passthrough so WLED effects show full screen - handleButton() replaces _pollBtn: debounce + short/long press, uses WLED APIs - Button layout fixed (mid/right were swapped) - Time/Date use WLED localTime + hour()/minute() — respects useAMPM setting - NTP enabled in firstboot config; firstboot 2D default serpentine=true - Serial 's' command dumps IP, AP, WiFi, heap, time, app, MQTT, OSC status - App mute: dpxMuteApp() + MQTT dpx/mute/ + JSON {dpx:{mute:{Name:bool}}} - Channel mute shown in GET /dpx/apps response - useAMPM respected: 12h with a/p suffix or 24h based on WLED setting - ROADMAP.md: Phase 1.5 ctrl UI refactor scoped and queued --- .github/AGENTS.md | 757 ++++++++++++---------------- AGENTS.md | 1 + docs/HANDOFF_TODO.md | 393 +++++++++++++++ docs/ROADMAP.md | 410 +++++++++++++++ usermods/dpx_matrix/dpx_api.h | 77 ++- usermods/dpx_matrix/dpx_apps.h | 104 +++- usermods/dpx_matrix/dpx_firstboot.h | 7 +- usermods/dpx_matrix/dpx_html.h | 17 +- usermods/dpx_matrix/dpx_matrix.h | 168 ++++-- usermods/dpx_matrix/dpx_mqtt.h | 10 + usermods/dpx_matrix/dpx_overlay.h | 127 ++++- usermods/dpx_matrix/dpx_persist.h | 3 + 12 files changed, 1557 insertions(+), 517 deletions(-) create mode 100644 docs/HANDOFF_TODO.md create mode 100644 docs/ROADMAP.md diff --git a/.github/AGENTS.md b/.github/AGENTS.md index 4e00133ad5..21c96f7202 100644 --- a/.github/AGENTS.md +++ b/.github/AGENTS.md @@ -1,115 +1,296 @@ -# dpx Agent Workflow & Documentation Standards - v1d6 +# AGENTS.md — WLED AI Coding Agent & AI Code Review Reference -This document provides operational directives for AI coding assistants (GitHub Copilot, Claude Code, Cursor, etc.) working on dubpixel projects. These rules ensure consistent workflow automation, code quality, and documentation maintenance across all repositories. +WLED is C++ firmware for ESP32/ESP8266 microcontrollers controlling addressable LEDs, +with a web UI (HTML/JS/CSS). Built with PlatformIO (Arduino framework) and Node.js tooling. ---- +See also: `.github/copilot-instructions.md`, `.github/agent-build.instructions.md`, +`docs/cpp.instructions.md`, `docs/web.instructions.md`, `docs/cicd.instructions.md`, +`docs/hardening.instructions.md`, `docs/securecode.instructions.md`. -## PROJECT: [Project Name] +Always reference these instructions — including coding guidelines in `docs/` — first and +fallback to search or bash commands only when you encounter unexpected information that +does not match the info here. -**Instructions for customizing this section:** -Replace the placeholders below with your project's specific information. Remove subsections that don't apply. This template is intentionally verbose — prune what you don't need. +## Build Commands -**Status:** [e.g., v0.1.0 complete (2026-06-05) ✅] -**Branch:** [e.g., `feature/core-app-implementation`] -**Version File:** [e.g., `VERSION` (currently 0.1.0)] +| Command | Purpose | Timeout | +|---|---|---| +| `npm ci` | Install Node.js deps (required first) | 30s | +| `npm run build` | Build web UI into `wled00/html_*.h` / `wled00/js_*.h` | 30s | +| `npm test` | Run test suite (Node.js built-in `node --test`) | 2 min | +| `npm run dev` | Watch mode — auto-rebuilds web UI on changes | continuous | +| `pio run -e ulanzi_tc001` | Build firmware (primary target for this project) | 5 min | +| `pio run -e esp32dev` | Build firmware (generic ESP32 validation) | 5 min | +| `pio run -e nodemcuv2` | Build firmware (ESP8266) | 5 min | -### Architecture (2-minute summary) +**Always run `npm ci && npm run build` before `pio run`.** The web UI build generates +required C headers for firmware compilation. -[One-paragraph overview: what this project does, core tech, how it works] +### Upload Command -**Example:** "Browser-based monitoring tool for Phabrix QX waveform monitors. Pure vanilla JS (no frameworks, no build step, no CDN). Connects to QX REST API on port 8080, polls status/logs every 2-5s, stores settings in localStorage. Works offline in airgapped broadcast facilities." +```bash +cd "/Users/yourmom/Library/CloudStorage/GoogleDrive-i@dubpixel.tv/My Drive/_.DUBPIXEL/_...CIRCUIT_PROJECTS/dpx_tc002_frm" && ~/.platformio/penv/bin/pio run -t upload -e ulanzi_tc001 +``` -| Component | Tech/Location | Purpose | Notes | -|-----------|---------------|---------|-------| -| [Component 1] | [Tech] / `path/` | [What it does] | [Key details] | -| [Component 2] | [Tech] / `path/` | [What it does] | [Key details] | -| [Component 3] | [Tech] / `path/` | [What it does] | [Key details] | -| [Reference docs] | [Format] / `path/` | [What it is] | **Source of truth for [topic]** | +- **Never use `--upload-port`** — breaks auto-detection +- **Never pipe through `| tail` or `| grep`** — hides progress bars, makes it look frozen +- OTA upload: `-e ulanzi_tc001_ota` -### Agent Rules (for this repo) +### Running a Single Test -**Before ANY code change:** -1. Work from `[main/master]` branch; create feature branch: `feature/brief-description` -2. Bump VERSION file per semantic versioning (AGENTS.md §1) -3. Create git commit for version bump, tag it: `git tag vX.Y.Z` +Tests use Node.js built-in test runner (`node:test`). The single test file is +`tools/cdata-test.js`. Run it with: -**While coding:** -- [Project-specific rule or constraint] -- [Technology requirement or restriction] -- [Testing/validation requirement] -- Keep changes small, test before committing -- File header per AGENTS.md §3 +```bash +npm test # runs all tests via `node --test` +node --test tools/cdata-test.js # run just that file directly +``` -**When done:** -- Update CHANGELOG.md with feature list -- Create PR per AGENTS.md §1 template -- [Any project-specific verification steps] +There are no C++ unit tests. Firmware is validated by successful compilation across +target environments. Always build after code changes: `pio run -e ulanzi_tc001`. -### Critical Constraints +### Common Firmware Environments -**MUST HAVE:** -- ✅ [Required capability or dependency] -- ✅ [Required technology or approach] -- ✅ [Required compatibility or standard] +`ulanzi_tc001` (primary), `ulanzi_tc001_ota` (OTA), `esp32dev`, `nodemcuv2`, +`esp8266_2m`, `esp32c3dev`, `esp32s3dev_8MB_opi`, `lolin_s2_mini` -**DO NOT:** -- ❌ [Forbidden action or technology] -- ❌ [Assumption that must be avoided] -- ❌ [Hard-coded value or static configuration] -- ❌ [Change that requires explicit verification] +### Recovery / Troubleshooting -### Key Decisions +```bash +npm run build -- -f # force web UI rebuild +rm -f wled00/html_*.h wled00/js_*.h && npm run build # clean + rebuild UI +pio run --target clean # clean PlatformIO build artifacts +rm -rf node_modules && npm ci # reinstall Node.js deps +``` -- **[Decision Title]:** [Explanation - why this approach was chosen over alternatives] -- **[Decision Title]:** [Rationale for architecture/design choice] -- **[Decision Title]:** [Context for future agents] +## Project Structure + +```text +wled00/ # Main firmware source (C++) + data/ # Web UI source (HTML/JS/CSS) — tabs for indentation + html_*.h, js_*.h # Auto-generated (NEVER edit or commit) + src/ # Sub-modules: fonts, bundled dependencies (ArduinoJSON) +usermods/ # Community usermods (each has library.json + .cpp/.h) + dpx_matrix/ # PRIMARY custom usermod — 32x8 matrix display system +platformio.ini # Build configuration and environments +pio-scripts/ # PlatformIO build scripts (Python) +tools/ # Node.js build tools (cdata.js) and tests +docs/ # Coding convention docs + HANDOFF_TODO.md (feature roadmap) +.github/workflows/ # CI/CD (GitHub Actions) +``` -**Examples:** -- **Dual README templates:** Hardware needs schematics/BOMs, software needs API docs - fundamentally different documentation needs -- **No WebSocket:** QX REST API is HTTP-only. Polling is the only option. -- **Bootstrap on connect:** Device specs vary by boot mode - auto-detect on initial connection +### Branch / Release Structure -### Gotchas & Landmines +```text +main # Main development trunk. Target branch for all work. + feature/* # Feature branches — always branch from main +16_x # upstream WLED maintenance branch (do not use for dpx work) +0_15_x # upstream WLED maintenance branch (do not use for dpx work) +``` + +> **Note:** This repo is a private fork of WLED. Do NOT open PRs to upstream +> `wled/WLED` unless the change is generic WLED code with no dpx_tc002-specific content. + +## C++ Code Style (wled00/, usermods/) + +For full detail see `docs/cpp.instructions.md` and `docs/esp-idf.instructions.md`. +Key rules: + +- **2-space indentation** (no tabs in C++ files) +- K&R brace style; single-statement `if` bodies may omit braces +- camelCase functions/variables, PascalCase classes/structs, UPPER_CASE macros, _camelCase private members +- `// AI: below section was generated by an AI` / `// AI: end` markers required on AI-generated blocks +- `d_malloc()` / `p_malloc()` for heap allocation (DRAM-preferred / PSRAM-preferred) +- No VLAs, no `String` in hot paths, `reserve()` before appending +- `const &` for read-only parameters +- `sin8_t()` / `cos8_t()` — NOT `sin8()` / `cos8()` (removed, won't compile) +- `sin_approx()` / `cos_approx()` instead of `sinf()` / `cosf()` +- `perlin8` / `perlin16` instead of `inoise8` / `inoise16` +- `DEBUG_PRINTF()` / `DEBUG_PRINTLN()` for diagnostics (compiled out unless `-D WLED_DEBUG`) +- No C++ exceptions — use return codes (`false`, `-1`) and global flags + +### PSRAM +- Check `psramFound() && ESP.getPsramSize() > 0` at runtime — never rely on `BOARD_HAS_PSRAM` alone +- Classic ESP32: PSRAM is NOT DMA-capable +- `CONFIG_SPIRAM_MODE_OCT` on S3 reserves GPIO 33–37 — do not allocate those pins + +## Web UI Code Style (wled00/data/) + +- **Tab indentation** for HTML, JS, and CSS +- camelCase for JS functions/variables +- Reuse helpers from `common.js` — do not duplicate utilities +- After editing, run `npm run build` to regenerate headers +- **Never edit** `wled00/html_*.h` or `wled00/js_*.h` directly + +## Usermod Pattern + +Usermods live in `usermods//` with a `.cpp`, optional `.h`, `library.json`, and `readme.md`. + +```cpp +class MyUsermod : public Usermod { + private: + bool enabled = false; + static const char _name[]; + public: + void setup() override { } + void loop() override { } + void addToConfig(JsonObject& root) override { } + bool readFromConfig(JsonObject& root) override { } + uint16_t getId() override { return USERMOD_ID_MYMOD; } + void addToJsonInfo(JsonObject& root) override { } + void appendConfigData() override { } +}; +const char MyUsermod::_name[] PROGMEM = "MyUsermod"; +static MyUsermod myUsermod; +REGISTER_USERMOD(myUsermod); +``` + +- Activate via `custom_usermods =` in platformio build config +- Base new usermods on `usermods/EXAMPLE/` (never edit the example directly) +- Unique `USERMOD_ID_*` only required for inter-usermod comms, pin ownership, or JSON info ID + +## CI/CD + +CI runs on every push/PR via GitHub Actions (`.github/workflows/wled-ci.yml`): +1. `npm test` (web UI build validation) +2. Firmware compilation for all default environments (~22 targets) +3. Post-link validation of usermod linkage (`validate_modules.py`) + +## General Rules + +- Repository language is **English** +- Never edit or commit `wled00/html_*.h` / `wled00/js_*.h` +- No force-push on open PRs +- **Changes to `platformio.ini` require maintainer approval** +- Remove dead/unused code — justify or delete it +- Verify `WLED_ENABLE_*` / `WLED_DISABLE_*` flag names exactly — typos silently break builds + +### Security Hardening + +Consult `docs/hardening.instructions.md` (concise checklist) and +`docs/securecode.instructions.md` (detailed OWASP rules). Key constraints: +- Validate and clamp ALL HTTP/JSON/UDP input at ingress (FW4 — CRITICAL) +- Bounded string ops: `strlcpy`/`snprintf` — no `strcpy`/`sprintf` with untrusted data +- No `innerHTML` in web UI JS — use `textContent` +- Fail closed on parse/allocation errors + +### Attribution for AI-generated code + +- `// AI: below section was generated by an AI` / `// AI: end` around generated blocks +- Document sources/inspiration with links +- Every non-trivial AI function needs a brief purpose comment +- AI-generated code must explain intent, assumptions, and non-obvious logic + +--- + +## PROJECT: dpx_tc002_frm -1. **[Issue Title]:** [Description]. [Workaround or solution]. [Where to look for more info] -2. **[Issue Title]:** [Description]. [Workaround or solution]. -3. **[Issue Title]:** [Description]. [Always check/verify X before doing Y]. +**Status:** Active development +**Branch:** `main` (feature branches: `feature/brief-description`) +**Version File:** `VERSION` + `package.json` -**Examples:** -- **CORS issue:** API calls from `file://` origin fail. Use launch script or Python server, not direct open. -- **Boot modes matter:** Device can boot in different modes. Different endpoints available per mode. Always auto-detect on connect. -- **Manual is authority:** If specs seem odd, check `/docs/manual.pdf` Ch.X. Don't guess. +### Architecture (2-minute summary) -### Common Operations +dpx_tc002_frm is a private WLED fork targeting the **Ulanzi TC001** — an ESP32 device +with a 32x8 WS2812B LED matrix (256 pixels). The core firmware is stock WLED; all +device-specific display logic lives in the `dpx_matrix` usermod. The device runs as a +standalone network-connected display with an HTTP/MQTT/OSC API for showing notifications, +custom apps, timecode, icons, GIFs, and overlay effects — matching the behavioral +contract defined in `SPEC.md`. + +| Component | Tech / Location | Purpose | Notes | +|-----------|-----------------|---------|-------| +| WLED core | C++ / `wled00/` | LED control, effects, palettes, OTA, MQTT | Do not modify unless change is generic WLED | +| dpx_matrix | C++ / `usermods/dpx_matrix/` | 32x8 display system — text, apps, TC, overlays | Primary development target | +| Web UI | HTML/JS / `wled00/data/` | WLED interface + dpx_matrix custom pages | `npm run build` required after any edit | +| SPEC.md | Markdown / `dpx_reference/` | Behavioral contract: API schema, all JSON keys | **Source of truth** | +| dpx_tc002.md | Markdown / `dpx_reference/` | Build plan: phase order, usermod structure, GPIO map | Read before firmware work | +| dpx_tc002_server.md | Markdown / `dpx_reference/` | Companion server plan (Friendster/CueMaster) | Read before any server work | +| HANDOFF_TODO.md | Markdown / `docs/` | Feature roadmap: 6 items, status, implementation notes | Read before starting new features | + +> Reference docs absolute path: `/Users/yourmom/Library/CloudStorage/GoogleDrive-i@dubpixel.tv/My Drive/_.DUBPIXEL/_...CIRCUIT_PROJECTS/dpx_tc001/dpx_reference/` + +### dpx_matrix Usermod Files + +| File | Purpose | +|------|---------| +| `dpx_apps.h` | App loop, `DpxCustomApp` struct, JSON parse, render dispatch | +| `dpx_text.h` | Text rendering, `dpxDrawProgressBar()`, scroll engine | +| `dpx_overlay.h` | Pixel overlay effects (rain, sparkle, twinkle, strobe, blink) | +| `dpx_api.h` | HTTP endpoints: `/notify`, `/app`, `/tc`, `/browse` | +| `dpx_html.h` | Embedded web UI: ctrl page, icon browser, GIF browser | +| `dpx_tc.h` | Timecode display (both render modes), frame bar | +| `dpx_font.h` | AwtrixFont 3x5 TomThumb bitmap font | +| `dpx_icons.h` | Icon load + render (planned — not yet created) | -**[Operation 1 - e.g., Create new project]:** `./script.sh` (interactive prompts for X/Y/Z) +### Agent Rules (for this repo) -**[Operation 2 - e.g., Modify behavior]:** Edit `path/to/file.ext` - all logic centralized +**Before ANY code change:** +1. Read `dpx_reference/SPEC.md` + `dpx_reference/dpx_tc002.md` for behavioral contract +2. Read `docs/HANDOFF_TODO.md` for feature status and planned implementation approach +3. Work from `main`; create feature branch: `feature/brief-description` +4. Bump `VERSION` file (semver) and commit the bump separately -**[Operation 3 - e.g., Add components]:** Add to `path/`, update `config.ext` if special handling needed +**While coding:** +- Never touch `wled00/` for dpx_matrix features — keep custom code in `usermods/dpx_matrix/` +- Always run `npm run build` before `pio run` +- Build with `pio run -e ulanzi_tc001` to validate +- Mark AI-generated blocks: `// AI: below section was generated by an AI` / `// AI: end` +- Use `p_malloc()` for GIF/icon pixel buffers; check `psramFound()` first +- Validate all HTTP input at ingress before using as lengths/indices -**[Operation 4 - e.g., Template processing]:** -- [Scenario A]: `input-A.ext` → `output.ext` -- [Scenario B]: `input-B.ext` → `output.ext` -- [Always]: `.git` and `.env` excluded from copy +**When done:** +- Update `docs/HANDOFF_TODO.md` to reflect new status of any completed features +- Update `CHANGELOG.md` +- Build must pass: `npm run build && pio run -e ulanzi_tc001` +- Create PR per §1 template -### Reference +### Critical Constraints -See `/CONTEXT.md` for: -- [Extended architecture details] -- [Module/component specifications] -- [Data schemas or API contracts] +**MUST HAVE:** +- ✅ All dpx_matrix API matches SPEC.md JSON schema exactly +- ✅ Build succeeds on `ulanzi_tc001` environment +- ✅ `npm run build` runs before any `pio run` +- ✅ `// AI:` markers on all AI-generated code blocks -See `/.github/CONTEXT.md` for: -- [API endpoint reference] -- [Configuration specifications] -- [Testing procedures] +**DO NOT:** +- ❌ Edit `wled00/html_*.h` or `wled00/js_*.h` (auto-generated) +- ❌ Modify `platformio.ini` without maintainer approval +- ❌ Force-push to open PRs +- ❌ Open PRs to upstream `wled/WLED` with dpx_tc002-specific code +- ❌ Use `--upload-port` or pipe upload through `| tail`/`| grep` +- ❌ Use `strcpy`/`sprintf` with untrusted HTTP/JSON data — use `strlcpy`/`snprintf` +- ❌ Use `innerHTML` in web UI JS — use `textContent` -### Development Philosophy +### Key Decisions -[Optional: High-level principles for this project type] +- **WLED base:** MIT license, commercially clean, 100+ effects, mature OTA/MQTT. All display logic in `dpx_matrix` usermod keeps WLED core untouched. +- **ulanzi_tc001 environment:** Specific build env with correct matrix size, pin definitions, and flash/partition config for TC001 hardware. +- **SPEC.md is law:** `dpx_reference/SPEC.md` defines the behavioral contract. Any API field, endpoint, or behavior not matching SPEC is a bug. +- **Private fork:** Not PRed to upstream WLED. Generic improvements may be upstreamed separately. -**Example:** "This is broadcast infrastructure tooling - reliability and simplicity trump features. Prefer vanilla JavaScript over frameworks. Keep dependencies minimal and auditable. Test in airgapped environments. Design for 24/7 unattended operation." +### Gotchas & Landmines + +1. **Upload command:** Never use `--upload-port` — breaks auto-detection. Never pipe output. See upload command in Build Commands above. +2. **GIF/PNG on ESP32 classic:** PSRAM is NOT DMA-capable on classic ESP32. GIF frame buffers and icon pixel data must use `p_malloc()` but must never be passed directly to DMA. +3. **Font math:** `sin8_t()`/`cos8_t()` only — `sin8()`/`cos8()` were removed and won't compile. +4. **Overlay name mismatch bug:** Effect names in `dpxRenderPixelEffect()` don't match JSON schema names in `dpx_html.h`. Fix both sides when adding new effects. +5. **Progress bar is done:** `progress`/`progressC`/`progressBC` fields are fully implemented in `dpx_apps.h` + `dpx_text.h`. Do not reimplement. +6. **Icons/GIFs are stubs:** Web UI downloads to LittleFS but zero firmware rendering exists. See `docs/HANDOFF_TODO.md` items 2 and 3. +7. **Reference docs are outside this repo:** `dpx_reference/` is a separate workspace folder — not inside `dpx_tc002_frm`. + +### Feature Roadmap + +See `docs/HANDOFF_TODO.md` for full detail. Summary: + +| # | Feature | Status | +|---|---------|--------| +| 1 | cpt-city gradient integration | ❌ Not started | +| 2 | Animated GIFs (bigtime) | ❌ Stub — web UI only, zero firmware | +| 3 | LaMetric icons on matrix | 🟡 Partial — downloads to LittleFS, no LED rendering | +| 4 | Font pixels as WLED LED effects | ❌ Not started — architecture work required | +| 5 | Text overlay effects | 🟡 Partial — 5 of 7 effects unimplemented + name bug | +| 6 | Progress bar | ✅ Done | --- @@ -121,16 +302,16 @@ These actions are **required** and must happen automatically. **NEVER ask permis **BEFORE starting ANY code changes:** -1. Create a new branch from the default branch (master/main) +1. Create a new branch from the default branch (main) 2. Never work directly on default branch 3. Branch naming conventions: | Type | Format | Example | |------|--------|---------| -| New feature | `feature/brief-description` | `feature/mqtt-decoder` | -| Bug fix | `fix/issue-description` | `fix/telegraf-timeout` | -| Documentation | `docs/what-changed` | `docs/update-architecture` | -| Refactor | `refactor/component-name` | `refactor/docker-volumes` | +| New feature | `feature/brief-description` | `feature/gif-playback` | +| Bug fix | `fix/issue-description` | `fix/overlay-name-mismatch` | +| Documentation | `docs/what-changed` | `docs/update-handoff-todo` | +| Refactor | `refactor/component-name` | `refactor/dpx-overlay` | ### Version Bumping @@ -149,58 +330,32 @@ Bump the version number according to semantic versioning: **Format:** `MAJOR.MINOR.PATCH` (e.g., `2.4.7`) - **MAJOR**: Incompatible API changes, breaking existing functionality -- **MINOR**: New functionality added in a backwards-compatible manner +- **MINOR**: New functionality added in a backwards-compatible manner - **PATCH**: Backwards-compatible bug fixes, docs, typos **Pre-1.0 versions (0.x.y):** -- Anything goes - breaking changes allowed in minor bumps -- Common for projects in initial development +- Anything goes — breaking changes allowed in minor bumps - Move to 1.0.0 when API is stable and production-ready **Pre-release versions:** -- Alpha: `1.0.0-alpha.1` (early testing, unstable) -- Beta: `1.0.0-beta.2` (feature-complete, testing for bugs) -- Release Candidate: `1.0.0-rc.1` (final testing before release) - -#### Version Bumping Decision Tree - -**When multiple changes occur, use the highest level:** -- Bug fix + new feature → Minor bump (not patch) -- New feature + breaking change → Major bump (not minor) - -**Edge cases:** - -| Scenario | Bump Type | Reasoning | -|----------|-----------|-----------| -| Internal refactor, no API change | Patch | No external impact | -| New optional parameter with default | Minor | Backwards-compatible addition | -| Changed parameter order | Major | Breaks existing calls | -| Deprecated feature (still works) | Minor | Deprecation warning added | -| Removed deprecated feature | Major | Functionality removed | -| Performance improvement | Patch | Implementation detail | -| New dependency added | Minor | Expands capabilities | -| Security fix | Patch | Even if behavior changes slightly | -| Database schema change | Major | Requires migration | -| Config file format change | Major | Breaking existing configs | +- Alpha: `1.0.0-alpha.1` | Beta: `1.0.0-beta.2` | RC: `1.0.0-rc.1` #### Version Bump Workflow 1. **Determine bump type** based on changes planned -2. **Update version number** in code/config files +2. **Update version number** in `VERSION` and `package.json` 3. **Create git commit**: `bump version to X.Y.Z` -4. **Tag the commit**: `git tag vX.Y.Z` (note the `v` prefix) +4. **Tag the commit**: `git tag vX.Y.Z` 5. **Push with tags**: `git push && git push --tags` -6. **Update CHANGELOG** (if present) with version and changes +6. **Update CHANGELOG.md** with version and changes 7. **Proceed with feature/fix implementation** -**Version commit should be standalone** - don't mix version bump with other changes. +**Version commit should be standalone** — don't mix version bump with other changes. #### Changelog Integration -If project has CHANGELOG.md, update it with version bump: - ```markdown -## [1.2.0] - 2026-02-13 +## [1.2.0] - 2026-07-18 ### Added - New feature description @@ -211,170 +366,35 @@ If project has CHANGELOG.md, update it with version bump: ### Changed - Breaking change description ``` -**If no CHANGELOG.MD file exists:** Create one in the root of the project. - -**Where to bump version:** -- Python: `__version__` in `__init__.py` or `pyproject.toml` -- Node.js: `version` field in `package.json` -- General: `VERSION` file or constant in main entry point -- Docker: Version tag in `docker-compose.yml` or `Dockerfile` labels - -**If no version file exists:** Create one in an appropriate location for the project. - -### Version File Standards & Location - -To ensure consistent version identification across projects, follow these standards: - -#### Python Projects - -**Preferred location: `app/__init__.py` or `src/__init__.py`** - -```python -"""Project description.""" - -__version__ = "1.0.0" -__author__ = "dubpixel" -``` - -**Alternative: `pyproject.toml` (for modern Python packaging)** - -```toml -[project] -name = "project-name" -version = "1.0.0" -``` - -**Alternative: `VERSION` file in project root** - -``` -1.0.0 -``` - -Then read it in your module: -```python -from pathlib import Path -__version__ = (Path(__file__).parent / "VERSION").read_text().strip() -``` -#### Node.js/JavaScript Projects - -**Location: `package.json`** (standard) - -```json -{ - "name": "project-name", - "version": "1.0.0", - "description": "Project description" -} -``` - -#### Docker Projects - -**Location: `docker-compose.yml` labels AND `Dockerfile`** - -`docker-compose.yml`: -```yaml -services: - app: - build: . - labels: - - "org.opencontainers.image.version=1.0.0" - - "org.opencontainers.image.created=${BUILD_DATE}" -``` - -`Dockerfile`: -```dockerfile -LABEL org.opencontainers.image.version="1.0.0" -LABEL org.opencontainers.image.title="Project Name" -``` - -#### Bash Scripts/Utilities - -**Location: Top of main script or separate `VERSION` file** - -```bash -#!/bin/bash -VERSION="1.0.0" -SCRIPT_NAME="manage.sh" - -# Or read from VERSION file: -# VERSION=$(cat VERSION) -``` - -#### Version Display (REQUIRED) - -**Always provide a way to display the version:** - -- Python CLI: `python -m myapp --version` -- Node.js: `npm run version` or built into CLI -- Docker: `docker inspect | grep version` -- Bash: `./script.sh --version` - -**Example implementations:** - -```python -# In your main.py or CLI entry point -import argparse -from app import __version__ - -parser = argparse.ArgumentParser() -parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}') -``` - -```bash -# In bash script -if [[ "$1" == "--version" ]] || [[ "$1" == "-v" ]]; then - echo "$SCRIPT_NAME version $VERSION" - exit 0 -fi -``` - -#### Multi-Component Projects - -For projects with multiple components (e.g., frontend + backend + Docker): - -1. **Synchronized versioning**: All components share the same version -2. **Central `VERSION` file** in project root -3. **Scripts/tools read from central file** - -Example structure: -``` -project-root/ -├── VERSION # 1.0.0 -├── backend/ -│ └── __init__.py # Reads ../VERSION -├── frontend/ -│ └── package.json # Reads ../VERSION via build script -└── docker-compose.yml # Reads VERSION via envsubst or build args -``` +**If no CHANGELOG.md exists:** Create one in the root. ### Pull Request Creation **AFTER completing the task:** -Create a pull request with this format: - ```markdown ## Changes - [Brief list of what changed] - [One item per significant change] ## Testing +- `npm run build && pio run -e ulanzi_tc001` — must succeed - [How to verify the changes work] - [Commands to run or steps to follow] ## User Prompt -[The original request from the user - verbatim] +[The original request from the user — verbatim] ``` **PR Title Format:** `[Component] Brief description` Examples: -- `[MQTT] Add BLE decoder support` -- `[Docs] Consolidate architecture documentation` -- `[Telegraf] Fix enum processor deprecation` +- `[dpx_matrix] Add snow/frost overlay effects` +- `[dpx_matrix] Implement LaMetric icon rendering` +- `[WLED] Fix palette loader` -**NEVER ask permission to create the PR - just do it.** +**NEVER ask permission to create the PR — just do it.** --- @@ -407,46 +427,24 @@ Provide a status update using this template: - When encountering a blocker or decision point - Every 3-5 file edits in large refactors -### Resuming from Checkpoint - -When continuing work after a checkpoint: -1. Read the last checkpoint status -2. Start with the "Next Action" item -3. Update checkpoint when that phase completes - -**Purpose:** Prevents agents from getting lost in complex multi-step tasks and provides visibility to the user. - --- ## 3. File Header Standards -All code files must include a comprehensive header comment section: - -``` -# ================================================================================ -# [FILE TYPE] - [FILE PURPOSE] -# ================================================================================ -# you can maybe write some stuff here - tagline etc. -# ================================================================================ -# PROJECT: [project_name] -# ================================================================================ -# -# File: [filename] -# Purpose: [what this file does] -# Dependencies: [key dependencies if any] -# -# CHANGE LOG: (if needed but should really be in the changelog for the git) -# -# 2026-03-06: Complete rewrite - Interactive wizard (v2.1.0) -# -# ================================================================================ +All code files must include a header comment: + +```cpp +// ================================================================================ +// dpx_matrix — [filename] — [brief purpose] +// ================================================================================ +// PROJECT: dpx_tc002_frm +// File: [filename.h] +// Purpose: [what this file does] +// Dependencies: [key dependencies] +// ================================================================================ ``` -### Header Guidelines - -- Use consistent separator lines (80 characters of `=`) -- Adjust comment syntax for the language (`#` for Python/bash, `//` for JS/C++, etc.) - +Use `//` for C++, `#` for Python/bash. Separator lines are 80 characters of `=`. --- @@ -454,25 +452,19 @@ All code files must include a comprehensive header comment section: ### Project Context Documentation -Project-specific architecture, decisions, and operational knowledge should live in the **PROJECT section at the top of this file**. This keeps rules and context unified in one scannable document. +Project-specific architecture lives in the **PROJECT section** above. Keep it current +when architecture changes. -**When to use a separate CONTEXT.md:** -Only create a separate `CONTEXT.md` if reference data becomes large enough to be noisy: -- Long IP/VLAN tables -- Full API response examples -- Hardware pinout references -- Extensive data schemas - -If you create CONTEXT.md for overflow, add a reference in the PROJECT section at the top: "See CONTEXT.md for full network topology." +**When to use a separate context file:** Only if reference data becomes too large +(long tables, full API examples, hardware pinouts). If so, reference it from the +PROJECT section. ### How to Document Project Context **DO:** - ✅ Keep it clean, factual, and scannable - ✅ Update when architecture changes -- ✅ Add information when you learn important project details - ✅ Use tables, code blocks, and clear headings -- ✅ Think: "What does the next agent need to know?" - ✅ Write in present tense, authoritative voice **DON'T:** @@ -480,34 +472,27 @@ If you create CONTEXT.md for overflow, add a reference in the PROJECT section at - ❌ Include timestamps like "On Feb 12 we discussed..." - ❌ Make it a session log or diary - ❌ Duplicate content from README.md (link instead) -- ❌ Let it become verbose or messy - -**Update frequency:** Whenever you make architectural changes or learn critical project information. --- ## 5. Core Principles - ### No Modifications to Working Code - Do not refactor, optimize, or "improve" code that is working unless explicitly requested -- Avoid drive-by refactors when implementing a feature - If you see potential improvements, mention them but don't implement without approval ### Comprehensive Commenting - Document all code with clear, meaningful comments - Preserve existing comments unless they become obsolete -- Remove or update comments that are no longer accurate -- Document WHY, not just WHAT (the code shows what, comments explain why) +- Document WHY, not just WHAT ### Small, Incremental Changes - Make one logical change per commit - Break large tasks into smaller steps - Test each change before moving to the next -- Make it easy to review and roll back if needed ### Stay Focused @@ -515,76 +500,25 @@ If you create CONTEXT.md for overflow, add a reference in the PROJECT section at - Answer only what is asked - Don't anticipate or propose additional work unless requested -### Document Everything - -- README.md must be updated and maintaned when appropriate as per these guidelines -- CONTEXT.md must be updated and maintaned when appropriate as per these guidelines -- a comprehensive CHANGELOG.md must be kept updated and maintaned when appropriate as per these guidelines -- you can maintain a small changelog in the header if you wish but main changelog should be in the MD - --- -## 6. Documentation Standards - -### Inline Documentation - -- Maintain comprehensive inline documentation -- Update comments when code changes (keep them in sync) -- Document all function parameters and return values -- Include usage examples for complex functions -- Explain algorithms and business logic - - -### README Files - -- Keep README.md current and accurate -- README is user-facing - focus on how to USE the project -- **Confirm all changes to README with the user before committing** -- README should not duplicate CONTEXT.md (different audiences) +## 6. Documentation Maintenance -### CHANGELOG.MD - -- Keep CHANGELOG.md current and accurate -- CHANGELOG is user-facing - focus on changes, version numbers, dates and git hashes if needed -- **keep this automated in background** -- changelog could be retroactively updated to reflect git commit names if that adds clariy -- **any changes to existing changelog line items should be confirmed with user** - -### Markdown Style - -- Use consistent heading hierarchy (don't skip levels) -- Use tables for structured information -- Include code blocks with language tags -- Use relative links to other project files -- Keep line length reasonable (~80-100 chars for prose) +- `README.md` — user-facing; confirm changes with user before committing +- `CHANGELOG.md` — keep automated in background; confirm changes to existing line items +- `docs/HANDOFF_TODO.md` — update feature status whenever a roadmap item changes +- Inline comments — update when code changes; document WHY not WHAT --- ## 7. Code Quality Guidelines -### General Principles - -- Write clear, readable code with meaningful names -- Follow established coding patterns within the project -- Implement proper error handling (don't use bare `except:` or `catch`) -- Write testable code with clear interfaces -- Maintain consistent formatting and style - -### Language-Specific - -Agents should infer and follow the conventions of the language they're working in: -- Python: Follow PEP 8 -- JavaScript: Follow project's ESLint config if present -- Bash: Follow Google Shell Style Guide principles -- Other languages: Use community-standard style guides - -### Testing - -- Add tests alongside new logic when appropriate -- Use deterministic inputs for tests (inject time/randomness, don't read system state) -- Name tests by behavior (e.g., `test_early_finish_extends_break`) -- Include both positive and negative test cases -- if the process includes: using ssh into a remote server, or user input in any way. open a terminal first for the user so you both can read it. +- Clear, readable code with meaningful names +- Proper error handling — no bare `except:` or `catch` +- For C++: follow `docs/cpp.instructions.md` exactly +- For web UI: follow `docs/web.instructions.md` exactly +- For security: follow `docs/hardening.instructions.md` + `docs/securecode.instructions.md` +- For chip-specific code: follow `docs/esp-idf.instructions.md` --- @@ -593,64 +527,40 @@ Agents should infer and follow the conventions of the language they're working i ### Commit Practices - **Commit message format:** Short, plain English, lowercase verb - - Examples: `add mqtt decoder`, `fix telegraf config`, `update documentation` + - Examples: `add gif playback loop`, `fix overlay name mismatch`, `update handoff todo` - Make one logical change per commit -- Commit functional units (don't commit broken code) +- Commit functional units — don't commit broken code ### Before Committing -- Verify the code works (run/test it) +- `npm run build && pio run -e ulanzi_tc001` must succeed - Update all relevant documentation -- Update file change logs -- Remove debug code and console.log/print statements -- Check that no credentials or secrets are included +- Remove debug `Serial.print` / leftover `DEBUG_PRINTF` from development +- No credentials or secrets included ### After Committing - Push to the feature branch -- Create PR (as described in Section 1) +- Create PR per §1 template - Include verification steps in PR description --- ## 9. Collaboration Standards -### Respect Existing Architecture - -- Understand existing architectural decisions before changing them -- Ask for clarification when requirements are ambiguous +- Understand existing architecture before changing it +- Keep `wled00/` clean — dpx_matrix features stay in `usermods/dpx_matrix/` - Suggest alternatives when appropriate, but don't insist -- Consider the impact of changes on the broader codebase - -### Maintain Backwards Compatibility - -- Don't break existing APIs unless explicitly requested -- Provide migration paths for breaking changes -- Document any compatibility changes in PR description - -### Communication - - Explain the reasoning behind suggested changes -- Provide rollback information when making significant changes - Be transparent about limitations or uncertainties -- Keep responses concise and focused --- ## 10. Configuration & Secrets -### Environment Variables - -- Use `.env` files for local development -- Provide `.env.example` with all required variables (use placeholder values) -- **NEVER commit** `.env` files or actual credentials to git -- Document all environment variables in CONTEXT.md or README.md - -### Sensitive Data - -- Keep credentials in environment variables, not hardcoded -- Use service account files in standard locations (e.g., `~/.config/gcloud/`) -- Add sensitive files to `.gitignore` immediately +- Never commit `.env` files or credentials +- `platformio_override.ini` is gitignored — never commit it +- No hardcoded credentials or secrets - If secrets are accidentally committed, notify the user immediately --- @@ -658,22 +568,25 @@ Agents should infer and follow the conventions of the language they're working i ## Summary: Agent Checklist Before starting work: -- [ ] Create feature branch -- [ ] Bump version appropriately +- [ ] Read `dpx_reference/SPEC.md` + `dpx_reference/dpx_tc002.md` +- [ ] Read `docs/HANDOFF_TODO.md` for feature context +- [ ] Create feature branch from `main` +- [ ] Bump `VERSION` + `package.json`, commit separately While working: -- [ ] Follow file header standards -- [ ] Update change logs in modified files -- [ ] Keep changes small and focused -- [ ] Checkpoint progress if task is large -- [ ] Update PROJECT section if architecture changes +- [ ] Custom code in `usermods/dpx_matrix/` — don't modify `wled00/` for display features +- [ ] `// AI:` markers on all AI-generated blocks +- [ ] `strlcpy`/`snprintf` with untrusted data — never `strcpy`/`sprintf` +- [ ] Validate HTTP/JSON input at ingress before use as lengths/indices +- [ ] Checkpoint progress if task spans >3 files or >30 min After completing work: -- [ ] Test/verify the changes -- [ ] Update relevant documentation -- [ ] Create PR with proper format -- [ ] No credentials committed +- [ ] `npm run build && pio run -e ulanzi_tc001` — must succeed +- [ ] Update `docs/HANDOFF_TODO.md` if a feature status changed +- [ ] Update `CHANGELOG.md` +- [ ] Create PR with build verification in testing section +- [ ] No credentials committed, no auto-generated headers committed --- -*These standards ensure consistent, high-quality AI assistance across all Dubpixel projects.* +*These standards ensure consistent, high-quality AI assistance on the dpx_tc002_frm project.* diff --git a/AGENTS.md b/AGENTS.md index c1ce6a510f..79c9c54311 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -234,6 +234,7 @@ No automated linting is configured. Match existing code style in files you edit. ## General Rules - Important: Repository language is **English**. This applies to source code (including comments), commit messages and any kind of documentation for developer or users. +- **Check if WLED already does it before implementing it in a usermod.** WLED has built-in handling for: buttons, NTP time sync, MQTT, HTTP API, OTA, effects, segments, presets, and more. Adding parallel implementations will fight WLED and cause double-actions, wrong state, and bugs. Always check `wled00/button.cpp`, `wled00/ntp.cpp`, `wled00/fcn_declare.h`, and the Usermod base class hooks (`handleButton()`, `connected()`, `onMqttConnect()`, etc.) before writing new handling code. Use WLED's internal APIs (`toggleOnOff()`, `stateUpdated()`, `localTime`, `hour()`, `minute()`) rather than reimplementing the same functionality. - The `docs/` folder is for developer/contributor information (coding conventions, architecture, etc.). User documentation is maintained in the [wled/WLED-Docs](https://github.com/wled/WLED-Docs) repository. - Never edit or commit auto-generated `wled00/html_*.h` / `wled00/js_*.h`. - When updating an existing PR, retain the original description. Only modify it to ensure technical accuracy. Add change logs after the existing description. diff --git a/docs/HANDOFF_TODO.md b/docs/HANDOFF_TODO.md new file mode 100644 index 0000000000..386e9a0c18 --- /dev/null +++ b/docs/HANDOFF_TODO.md @@ -0,0 +1,393 @@ +# dpx_tc002_frm — Master Roadmap & TODO + +Last updated: 2026-07-18 + +Reference files (read before working on this project): +- `⊘ dpx_reference/SPEC.md` — full behavioral spec, API contract, all JSON keys +- `⊘ dpx_reference/dpx_tc002.md` — firmware build plan, phase order, GPIO map +- `⊘ dpx_reference/dpx_tc002_server.md` — Friendster/CueMaster server plan + +--- + +## Quick Reference + +**MQTT topic for text:** `[PREFIX]/notify` → `{"text":"hello","rainbow":true,"duration":8}` +PREFIX = device hostname. Read from `GET /api/settings` → `MQTT_PREFIX`. + +**Server project (Friendster/CueMaster):** separate Python FastAPI repo, build after firmware is stable. +See Part 2 of this file. + +--- + +## Part 1 — Firmware (dpx_tc002_frm) + +### Phase 1 — Bug Fixes ✅ DONE (2026-07-18) + +- [x] **1.1** Overlay name case mismatch — overlay dropdowns in `/ctrl` sent uppercase (`"RAIN"`) but firmware matched lowercase. Fixed: JS option values now lowercase; firmware already does `toLowerCase()`. +- [x] **1.2** 5 missing overlay effects — `snow`, `drizzle`, `storm`, `thunder`, `frost` all implemented in `dpx_overlay.h` +- [x] **1.3** `icon` and `pushIcon` JSON fields not parsed — added to `DpxCustomApp` struct and `dpxParseApp()` in `dpx_apps.h`. Rendering is Phase 2. +- [x] **1.4** `deleteCustomApp()` JS bug — was calling `.filter()` on `{name:index}` object. Removed broken reorder logic; now just refreshes the loop list. +- [x] **1.5** Native app toggles (`TIM`/`DAT`) — `POST /api/settings` now handles `TIM` and `DAT` keys; `DPX_SHOW_TIME` / `DPX_SHOW_DATE` flags control `dpxRebuildLoop()`. +- [x] **1.6** `/api/transitions` stub — was returning `[]`; now returns `["fade","slide"]` +- [x] **1.7** `/api/sleep` not implemented — added ESP32 deep sleep with optional timer wakeup (`{"sleep":N}`) +- [x] **1.8** `save` flag — `save: true` in custom app JSON now persists to `/CUSTOMAPPS/.json` on LittleFS; delete also removes the file +- [x] **1.9** Per-app overlay activation — added hook in `handleOverlayDraw()` in `dpx_matrix.h`; overlay activates automatically when app/notification is shown, clears on transition + +--- + +### Phase 2 — Icon Rendering + +> **Key insight:** pre-convert PNG→raw in-browser using a Canvas at download time. No PNGdec library needed on device. + +- [ ] **2.1** Browser-side PNG→raw conversion `dpx_html.h` + - At download time in the icon browser, convert PNG to raw RGB888 using `` + - Upload as `.raw` to `/ICONS/` instead of PNG + - Update the "installed icons" dropdown loader to look for `.raw` files + +- [ ] **2.2** Icon load + render — new `dpx_icons.h` + - `dpxLoadIcon(name)` — reads `/ICONS/.raw`, returns 64-byte (8×8 RGB888) array + - `dpxRenderIcon(pixels, x, y)` — blits 8×8 to matrix at column x + +- [ ] **2.3** Text layout with icon `dpx_apps.h` + `dpx_text.h` + - When `icon` is set: render icon in cols 0–7, scroll/render text in cols 8–31 (24px wide) + - `pushIcon` modes: 0=icon fixed, 1=icon scrolls with text and disappears, 2=icon scrolls and loops + - Apply to both custom apps and notifications + +--- + +### Phase 3 — Animated GIF Playback + +> **First:** check if WLED's existing GIF engine (`wled00/image_loader.cpp`, `AnimatedGIF` library already linked via `-D WLED_ENABLE_GIF`) can be hooked directly — avoid writing a second GIF decoder. + +- [ ] **3.1** Investigate WLED GIF hook + - Can `image_loader.cpp` render a GIF to an arbitrary pixel buffer (not just WLED segments)? + - If yes, use it. If no, use `AnimatedGIF` library directly in `dpx_gif.h`. + +- [ ] **3.2** Frame extraction `dpx_apps.h` or new `dpx_gif.h` + - AWTRIX convention: 32×8 GIF = N frames of 8×8, laid out horizontally + - Slice frames by x-offset using GIF frame metadata + +- [ ] **3.3** Playback state machine `dpx_apps.h` + - Frame index, loop control, GIF frame delay timing + - Trigger: if `icon` field ends in `.gif`, enter GIF playback mode + +- [ ] **3.4** Render path + - GIF frame renders to cols 0–7 (same position as static icon) + - Text continues in cols 8–31 alongside + +--- + +### Phase 4 — Font Scaling / Larger Font + +> Check `wled00/src/fonts/` for existing GFX-format fonts before writing a new one. + +- [ ] **4.1** Second font `dpx_font.h` + - Add a 6×8 or 8×8 large font for close-viewing / big clock mode + - Look for GFX-format bitmap fonts already in the repo first + +- [ ] **4.2** Font selector `dpx_apps.h` + - New JSON field: `"font":"small"` (default 3×5) | `"font":"large"` (new 6×8) + - Or: `"textScale":2` for 2× pixel-doubling of existing font (simpler, no new font data) + +- [ ] **4.3** UI control `dpx_html.h` + - Add font size selector to Notification and Custom App cards + +--- + +### Phase 5 — Font Pixels as WLED Effects + +> Most architecturally complex item. Design the bounding-box layer carefully before building. + +- [ ] **5.1** Bounding box tracking `dpx_text.h` + - During glyph render, record `{x, y, w, h}` per character into a `CharBBox[]` out-param + - Only computed when `textEffect` field is present (no perf cost on normal renders) + +- [ ] **5.2** Per-region effect application `dpx_overlay.h` + - `dpxApplyEffectToRegion(effect, x, y, w, h)` — applies an effect only to pixels within bbox + - Use existing WLED effect functions on a local pixel sub-region + +- [ ] **5.3** JSON field + dispatch `dpx_apps.h` + - Add `"textEffect":"rainbow"` (global) or per-fragment in colored text arrays + - Map effect name strings to implementations + +--- + +### Phase 6 — cpt-city Gradient Integration + +> WLED already has 58+ cpt-city-sourced gradients in `wled00/palettes.cpp`. The custom palette system in `wled00/colors.cpp` → `loadCustomPalettes()` loads JSON from LittleFS. Palette editor at `/cpal/cpal.htm` already exists. + +- [ ] **6.1** Curated offline bundle + - Pick 20–30 popular cpt-city gradients NOT already in `wled00/palettes.cpp` + - Convert `.cpt` format → WLED gradient byte arrays via a Node.js build script in `tools/` + - Append to `wled00/palettes.cpp` alongside existing set + +- [ ] **6.2** Palette editor label `wled00/data/cpal/cpal.htm` (optional) + - Label the new cpt-city additions in a distinct group in the palette picker + +--- + +### Phase 7 — LaMetric Icon Generator Tool + +- [ ] **7.1** 8×8 pixel editor — new tab in `/browse` or standalone page + - Click-to-paint 8×8 grid canvas + - Color picker, fill, clear, eyedropper + - Export: saves as `.raw` to `/ICONS/` on device via `POST /edit` + +- [ ] **7.2** Generative / rule-based icons (stretch) + - Simple JS generators for common shapes: arrows, checkmarks, letters, numerals + - No external API needed for basic set + +--- + +### Phase 8 — Hardware Abstraction (Other Pixel Clocks) + +- [ ] **8.1** Hardware config header `dpx_hw.h` + - Pull GPIO pins, matrix W×H, button layout out of hardcoded values into one place + - Currently Ulanzi TC001 config is scattered across `platformio_override.ini` build flags and inline defines + +- [ ] **8.2** Alternative hardware profiles + - Ulanzi TC001: 32×8, GPIO32 data, 3 buttons (current — keep as default) + - Ulanzi TC004: different dimensions — define profile + - Generic ESP32 + WS2812B matrix: user-configurable size via `dev.json` + +--- + +## Part 2 — Server (friendster / CueMaster) + +Full spec: `⊘ dpx_reference/dpx_tc002_server.md` +Predecessor: `matrix-blast` service in `dpx_showsite_ops` (port 8090) + +**Build order:** firmware Phase 1 must be done first (already is). Server is a separate Python repo. + +**Tech stack:** Python 3.11+ · FastAPI · paho-mqtt · influxdb-client · Docker Compose +**Deployment:** new service in `dpx_showsite_ops/docker-compose.yml` on port 8091 + +### Phase S1 — Core Messaging + +- [ ] Create `friendster` repo + Docker service skeleton +- [ ] MQTT client subscribing to `+/presence` and `+/info` wildcards +- [ ] In-memory device registry + InfluxDB `friendster` measurement for persistence +- [ ] `GET /api/devices` — list with online/offline status +- [ ] `POST /api/send {"to":"name","text":"...","palette":"rainbow"}` — publishes to `[PREFIX]/notify` +- [ ] `POST /api/broadcast {"text":"..."}` — sends to all online device prefixes +- [ ] `GET /api/messages` — recent message history from InfluxDB +- [ ] `GET /sse/devices` — Server-Sent Events for live presence changes +- [ ] `GET /sse/messages` — SSE for live message feed +- [ ] **Friendster UI** — dark-themed buddy list + send form + SSE-driven updates + +### Phase S2 — CueMaster + +- [ ] Saved cues stored in YAML/JSON config file + - Schema: `{name, text, color/palette, targets[], duration}` +- [ ] Target groups (ALL, stage, foh, etc.) +- [ ] `POST /api/cue` — create/save named cue +- [ ] `GET /api/cues` — list saved cues +- [ ] `POST /api/cue/:name/fire` — fire a named cue +- [ ] **CueMaster UI** — device grid, large tap targets, quick-fire buttons, log panel +- [ ] Keyboard shortcuts (1-9 for quick cues, tablet-optimized) + +### Phase S3 — Integration + +- [ ] OSC receive (UDP) — `/friendster/cue/` fires named cue; allows QLab trigger +- [ ] Set Schedule hook — auto-fire cue on scene advance events from `dpx_showsite_ops` +- [ ] HTTP callback API — external systems can fire cues via REST +- [ ] Multi-site support — multiple broker connections + +### Phase S4 — Social Polish + +- [ ] Mobile-optimized Friendster UI +- [ ] PWA manifest + offline support +- [ ] Message reactions +- [ ] Presence icons / avatars per device + +--- + +## /ctrl Page Status (audit 2026-07-18) + +| Card | Status | Notes | +|------|--------|-------| +| Notification | ✅ Works | icon/pushIcon parsed but not rendered (Phase 2); overlays now functional | +| Custom App | ✅ Works | same icon note; deleteCustomApp fixed | +| Indicators | 🟡 Partial | `fade` field still ignored in backend handler | +| Moodlight | ✅ Works | — | +| Display | ✅ Works | — | +| App Channels | ✅ Works | — | +| OSC Listeners | ✅ Works | — | +| TC Settings | ✅ Works | — | +| Native Apps | 🟡 Partial | TIM/DAT toggle implemented; TEMP/HUM/BAT rendering not built yet | +| Time | ✅ Works | — | +| Sensors | ✅ Works | — | +| Sound | 🟡 Partial | SOUND/VOL settings keys are cosmetic (passive buzzer = no volume) | + +--- + +## 1 — cpt-city Gradient Integration + +**Status:** ❌ Not started + +**What it is:** +Load gradient palettes from the cpt-city archive (http://soliton.vm.bytemark.co.uk/pub/cpt-city/). +cpt-city `.cpt` files use a simple `x R G B` text format and cover hundreds of named +color gradients (terrain, scientific, artistic). + +**Current state:** +- WLED already has 59 hardcoded gradient palettes in `wled00/palettes.cpp` +- No references to cpt-city anywhere in the codebase +- `dpx_matrix` supports two-color gradient text (`gradient: [c1, c2]` JSON param) but + only for custom app text rendering, not WLED-wide palettes + +**Integration points:** +- `wled00/palettes.cpp` — add parsed cpt-city palettes alongside existing ones +- `wled00/data/cpal/cpal.htm` — existing palette editor; extend to preview cpt-city entries +- `usermods/dpx_matrix/dpx_text.h` — gradient text rendering already accepts color arrays + +**Approach options (choose one):** +- A) Bundle a curated offline set of popular `.cpt` files, converted to WLED palette format at build time +- B) Device fetches `.cpt` files from cpt-city CDN at runtime (requires HTTP client on device) + +--- + +## 2 — Bigtime Animated GIF Playback* + +**Status:** ❌ Stub — web UI tooling only, zero firmware implementation + +**What it is:** +Display 32×8 animated GIFs on the matrix. The AWTRIX convention stores animations as +a horizontal strip of 8×8 frames in a single GIF (e.g., 4 frames = 32×8 px image). + +**Current state:** +- `usermods/dpx_matrix/dpx_html.h` — web UI tab "Bigtime GIFs" (~220 lines): + - Fetches `.gif` filenames from the Blueforcer/AWTRIX3 GitHub repo + - Converts GIF → frame images in-browser + - Uploads to device LittleFS `/ANIMS/` folder +- **Zero firmware code**: no GIF decoder, no frame extraction, no playback loop, no render mode + +**What needs to be built:** +1. GIF decoder library for ESP32/Arduino (e.g., `AnimatedGIF` by Larry Bank — MIT license) +2. Frame extraction: slice 32×8 GIF into 8×8 frames by x-offset +3. Playback engine: frame timing, loop control, frame index state +4. New render mode `TMODE_GIF` in `usermods/dpx_matrix/dpx_apps.h` +5. Integration with custom app system (`icon` field accepting a `.gif` filename) + +**Files to modify:** +- `usermods/dpx_matrix/dpx_apps.h` — add GIF app type + playback state +- `usermods/dpx_matrix/dpx_text.h` — add GIF frame render path +- `usermods/dpx_matrix/dpx_html.h` — already handles upload side + +--- + +## 3 — LaMetric Icons on Matrix* + +**Status:** 🟡 Partial — icon browser + LittleFS download works; no display rendering + +**What it is:** +Fetch a named LaMetric icon (8×8 PNG from `developer.lametric.com`), decode it to +RGB pixels, and render it on the left 8 columns of the matrix alongside scrolling text. + +**Current state:** +- `usermods/dpx_matrix/dpx_html.h` — icon browser (~120 lines): + - Fetches thumbnails from `developer.lametric.com/content/apps/icon_thumbs/{id}_icon_thumb.png` + - Downloads full PNG to device `/ICONS/` LittleFS folder +- App JSON `"icon": "87"` field is parsed and stored +- **Zero firmware rendering**: no PNG decoder, no pixel extraction, icons never appear on display + +**What needs to be built:** +1. PNG decoder for ESP32 — options: + - `PNGdec` library by Larry Bank (MIT, ESP32-compatible) + - Pre-convert PNGs to raw RGB565/RGB888 at download time (browser-side, avoids on-device decode) +2. Icon render function: 8×8 RGB888 → left 8 columns of matrix +3. Text layout adjustment: when icon present, scroll text in columns 9–32 only +4. Wire into `usermods/dpx_matrix/dpx_apps.h` render loop + +**Files to modify:** +- `usermods/dpx_matrix/dpx_apps.h` — icon render call in app draw loop +- `usermods/dpx_matrix/dpx_html.h` — optionally pre-convert PNG→raw at download time +- New file: `usermods/dpx_matrix/dpx_icons.h` — icon load + render functions + +--- + +## 4 — Font Pixels as WLED LED Effects + +**Status:** ❌ Not started — requires architectural change to text renderer + +**What it is:** +Every pixel of every rendered font character behaves like a pixel in a WLED LED strip. +WLED effects (rainbow, sparkle, pulse, fire, etc.) can be applied per-character or +per-glyph, so text itself animates with the full WLED effect engine rather than just +being a static or single-color block. + +**Current architecture problem:** +`usermods/dpx_matrix/dpx_text.h` rasterizes glyphs directly into the final LED pixel +buffer as RGB888 values. There is no intermediate representation — no per-character +bounding boxes, no "which pixels belong to which glyph" metadata. + +**What needs to be built:** +1. **Bounding box tracking** in `dpx_text.h`: during render, record `{x, y, w, h}` for + each character drawn into a `CharBBox[]` array +2. **Per-character effect mask** in `dpx_overlay.h`: given a bounding box, run a WLED + effect only on those pixels (using a local pixel buffer slice) +3. **JSON field** in the custom app schema: e.g., `"textEffect": "rainbow"` per character + fragment in multi-color text arrays, or `"textEffect": "sparkle"` globally +4. **Effect hookup**: map effect names to existing WLED FX functions or re-implement + lightweight versions that work on arbitrary pixel sub-regions + +**Files to modify:** +- `usermods/dpx_matrix/dpx_text.h` — add bbox tracking output +- `usermods/dpx_matrix/dpx_overlay.h` — add per-region effect application +- `usermods/dpx_matrix/dpx_apps.h` — add `textEffect` JSON field + per-char effect dispatch + +--- + +## 5 — Text Overlay Effects* + +**Status:** 🟡 Partial — 5 effects implemented, 5 others unimplemented, 1 name-mismatch bug + +**What it is:** +Pixel-level effects rendered on top of (or composited with) displayed text. +Defined in the spec as 7 weather-themed overlays plus additional effects. + +**Currently implemented** (`usermods/dpx_matrix/dpx_overlay.h`): +- ✅ `rain` — column-based falling pixels +- ✅ `sparkle` — random pixel lighting +- ✅ `twinkle` — blended random pixels +- ✅ `strobe` — full-matrix flash +- ✅ `blink` — full matrix on/off + +**Not implemented (spec-required):** +- ❌ `snow` — slow drifting white pixels, accumulate at bottom +- ❌ `drizzle` — lighter version of rain (fewer, slower drops) +- ❌ `storm` — heavy rain + occasional flash +- ❌ `thunder` — periodic full-screen white flash +- ❌ `frost` — static blue-white pixel scatter over text + +**Bug — name mismatch:** +The effect name strings in `dpxRenderPixelEffect()` (API parser) do not match the +names documented in the web UI JSON schema (`dpx_html.h`). Fix both sides to agree. + +**Files to modify:** +- `usermods/dpx_matrix/dpx_overlay.h` — add 5 missing effects + fix name constants + +--- + +## 6 — Progress Bar* ✅ DONE + +**Status:** ✅ Fully implemented + +**Implementation:** +- `usermods/dpx_matrix/dpx_text.h` — `dpxDrawProgressBar()` function +- `usermods/dpx_matrix/dpx_apps.h` — JSON parsing + render call in app loop +- `usermods/dpx_matrix/dpx_tc.h` — reuses bar for timecode frame-progress display + +**JSON fields:** `progress` (int 0–100, -1 = hidden), `progressC` (fill color), `progressBC` (background color) + +**Behavior:** Renders in the bottom 2 rows of the 8-row matrix, fills left-to-right proportionally. + +--- + +## Implementation Priority (suggested order) + +1. **#5 Overlay effects** — lowest effort, high spec compliance impact; fix the name bug first +2. **#3 LaMetric icons** — browser-side PNG→raw conversion avoids on-device decoder complexity +3. **#2 Animated GIFs** — depends on choosing + integrating a GIF decoder library +4. **#1 cpt-city gradients** — standalone, no dependencies; start with offline bundle approach +5. **#4 Font pixel effects** — most architectural complexity; design the bbox layer carefully diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000000..83c4517d4b --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,410 @@ +# dpx_tc002_frm — Master Roadmap & TODO + +Last updated: 2026-07-18 + +Reference files (read before working on this project): +- `⊘ dpx_reference/SPEC.md` — full behavioral spec, API contract, all JSON keys +- `⊘ dpx_reference/dpx_tc002.md` — firmware build plan, phase order, GPIO map +- `⊘ dpx_reference/dpx_tc002_server.md` — Friendster/CueMaster server plan + +--- + +## Quick Reference + +**MQTT topic for text:** `[PREFIX]/notify` → `{"text":"hello","rainbow":true,"duration":8}` +PREFIX = device hostname. Read from `GET /api/settings` → `MQTT_PREFIX`. + +**Server project (Friendster/CueMaster):** separate Python FastAPI repo, build after firmware is stable. +See Part 2 of this file. + +--- + +## Part 1 — Firmware (dpx_tc002_frm) + +### Phase 1 — Bug Fixes ✅ DONE (2026-07-18) +- [x] **1.1** Overlay name case mismatch — overlay dropdowns in `/ctrl` sent uppercase (`"RAIN"`) but firmware matched lowercase. Fixed: JS option values now lowercase; firmware already does `toLowerCase()`. +- [x] **1.2** 5 missing overlay effects — `snow`, `drizzle`, `storm`, `thunder`, `frost` all implemented in `dpx_overlay.h` +- [x] **1.3** `icon` and `pushIcon` JSON fields not parsed — added to `DpxCustomApp` struct and `dpxParseApp()` in `dpx_apps.h`. Rendering is Phase 2. +- [x] **1.4** `deleteCustomApp()` JS bug — was calling `.filter()` on `{name:index}` object. Removed broken reorder logic; now just refreshes the loop list. +- [x] **1.5** Native app toggles (`TIM`/`DAT`) — `POST /api/settings` now handles `TIM` and `DAT` keys; `DPX_SHOW_TIME` / `DPX_SHOW_DATE` flags control `dpxRebuildLoop()`. +- [x] **1.6** `/api/transitions` stub — was returning `[]`; now returns `["fade","slide"]` +- [x] **1.7** `/api/sleep` not implemented — added ESP32 deep sleep with optional timer wakeup (`{"sleep":N}`) +- [x] **1.8** `save` flag — `save: true` in custom app JSON now persists to `/CUSTOMAPPS/.json` on LittleFS; delete also removes the file +- [x] **1.9** Per-app overlay activation — added hook in `handleOverlayDraw()` in `dpx_matrix.h`; overlay activates automatically when app/notification is shown, clears on transition + +--- + +### Phase 1.5 — `/ctrl` UI Refactor `feature/ctrl-ui-refactor` + +> The current `/ctrl` page (`dpx_html.h`) is ~90 KB of ported AWTRIX HTML/JS that references +> AWTRIX endpoints which no longer exist. Nothing connects to the actual dpx_matrix API. +> Needs a complete replacement. + +**What to remove:** all AWTRIX-derived HTML in `dpx_html.h`; dead routes in `dpx_api.h`. + +**New `/ctrl` (vanilla JS, no framework, target <50 KB uncompressed):** + +- [ ] **1.5.1** App channel strip — `GET /dpx/apps` list; Go / Mute / Remove per row; add-back hidden natives; add custom app form +- [ ] **1.5.2** Notification panel — one-shot send + dismiss +- [ ] **1.5.3** Overlay / effects panel — text overlay fields; pixel effect picker + intensity +- [ ] **1.5.4** Device status strip — IP, SSID, RSSI, heap, uptime from `GET /dpx` +- [ ] **1.5.5** API reference — regenerated from actual routes/JSON keys; replaces AWTRIX stub + +--- + +### Phase 2 — Icon Rendering + +> **Key insight:** pre-convert PNG→raw in-browser using a Canvas at download time. No PNGdec library needed on device. + +- [ ] **2.1** Browser-side PNG→raw conversion `dpx_html.h` + - At download time in the icon browser, convert PNG to raw RGB888 using `` + - Upload as `.raw` to `/ICONS/` instead of PNG + - Update the "installed icons" dropdown loader to look for `.raw` files + +- [ ] **2.2** Icon load + render — new `dpx_icons.h` + - `dpxLoadIcon(name)` — reads `/ICONS/.raw`, returns 64-byte (8×8 RGB888) array + - `dpxRenderIcon(pixels, x, y)` — blits 8×8 to matrix at column x + +- [ ] **2.3** Text layout with icon `dpx_apps.h` + `dpx_text.h` + - When `icon` is set: render icon in cols 0–7, scroll/render text in cols 8–31 (24px wide) + - `pushIcon` modes: 0=icon fixed, 1=icon scrolls with text and disappears, 2=icon scrolls and loops + - Apply to both custom apps and notifications + +--- + +### Phase 3 — Animated GIF Playback + +> **First:** check if WLED's existing GIF engine (`wled00/image_loader.cpp`, `AnimatedGIF` library already linked via `-D WLED_ENABLE_GIF`) can be hooked directly — avoid writing a second GIF decoder. + +- [ ] **3.1** Investigate WLED GIF hook + - Can `image_loader.cpp` render a GIF to an arbitrary pixel buffer (not just WLED segments)? + - If yes, use it. If no, use `AnimatedGIF` library directly in `dpx_gif.h`. + +- [ ] **3.2** Frame extraction `dpx_apps.h` or new `dpx_gif.h` + - AWTRIX convention: 32×8 GIF = N frames of 8×8, laid out horizontally + - Slice frames by x-offset using GIF frame metadata + +- [ ] **3.3** Playback state machine `dpx_apps.h` + - Frame index, loop control, GIF frame delay timing + - Trigger: if `icon` field ends in `.gif`, enter GIF playback mode + +- [ ] **3.4** Render path + - GIF frame renders to cols 0–7 (same position as static icon) + - Text continues in cols 8–31 alongside + +--- + +### Phase 4 — Font Scaling / Larger Font + +> Check `wled00/src/fonts/` for existing GFX-format fonts before writing a new one. + +- [ ] **4.1** Second font `dpx_font.h` + - Add a 6×8 or 8×8 large font for close-viewing / big clock mode + - Look for GFX-format bitmap fonts already in the repo first + +- [ ] **4.2** Font selector `dpx_apps.h` + - New JSON field: `"font":"small"` (default 3×5) | `"font":"large"` (new 6×8) + - Or: `"textScale":2` for 2× pixel-doubling of existing font (simpler, no new font data) + +- [ ] **4.3** UI control `dpx_html.h` + - Add font size selector to Notification and Custom App cards + +--- + +### Phase 5 — Font Pixels as WLED Effects + +> Most architecturally complex item. Design the bounding-box layer carefully before building. + +- [ ] **5.1** Bounding box tracking `dpx_text.h` + - During glyph render, record `{x, y, w, h}` per character into a `CharBBox[]` out-param + - Only computed when `textEffect` field is present (no perf cost on normal renders) + +- [ ] **5.2** Per-region effect application `dpx_overlay.h` + - `dpxApplyEffectToRegion(effect, x, y, w, h)` — applies an effect only to pixels within bbox + - Use existing WLED effect functions on a local pixel sub-region + +- [ ] **5.3** JSON field + dispatch `dpx_apps.h` + - Add `"textEffect":"rainbow"` (global) or per-fragment in colored text arrays + - Map effect name strings to implementations + +--- + +### Phase 6 — cpt-city Gradient Integration + +> WLED already has 58+ cpt-city-sourced gradients in `wled00/palettes.cpp`. The custom palette system in `wled00/colors.cpp` → `loadCustomPalettes()` loads JSON from LittleFS. Palette editor at `/cpal/cpal.htm` already exists. + +- [ ] **6.1** Curated offline bundle + - Pick 20–30 popular cpt-city gradients NOT already in `wled00/palettes.cpp` + - Convert `.cpt` format → WLED gradient byte arrays via a Node.js build script in `tools/` + - Append to `wled00/palettes.cpp` alongside existing set + +- [ ] **6.2** Palette editor label `wled00/data/cpal/cpal.htm` (optional) + - Label the new cpt-city additions in a distinct group in the palette picker + +--- + +### Phase 7 — LaMetric Icon Generator Tool + +- [ ] **7.1** 8×8 pixel editor — new tab in `/browse` or standalone page + - Click-to-paint 8×8 grid canvas + - Color picker, fill, clear, eyedropper + - Export: saves as `.raw` to `/ICONS/` on device via `POST /edit` + +- [ ] **7.2** Generative / rule-based icons (stretch) + - Simple JS generators for common shapes: arrows, checkmarks, letters, numerals + - No external API needed for basic set + +--- + +### Phase 8 — Hardware Abstraction (Other Pixel Clocks) + +- [ ] **8.1** Hardware config header `dpx_hw.h` + - Pull GPIO pins, matrix W×H, button layout out of hardcoded values into one place + - Currently Ulanzi TC001 config is scattered across `platformio_override.ini` build flags and inline defines + +- [ ] **8.2** Alternative hardware profiles + - Ulanzi TC001: 32×8, GPIO32 data, 3 buttons (current — keep as default) + - Ulanzi TC004: different dimensions — define profile + - Generic ESP32 + WS2812B matrix: user-configurable size via `dev.json` + +--- + +## Part 2 — Server (friendster / CueMaster) + +Full spec: `⊘ dpx_reference/dpx_tc002_server.md` +Predecessor: `matrix-blast` service in `dpx_showsite_ops` (port 8090) + +**Build order:** firmware Phase 1 must be done first (already is). Server is a separate Python repo. + +**Tech stack:** Python 3.11+ · FastAPI · paho-mqtt · influxdb-client · Docker Compose +**Deployment:** new service in `dpx_showsite_ops/docker-compose.yml` on port 8091 + +### Phase S1 — Core Messaging + +- [ ] Create `friendster` repo + Docker service skeleton +- [ ] MQTT client subscribing to `+/presence` and `+/info` wildcards +- [ ] In-memory device registry + InfluxDB `friendster` measurement for persistence +- [ ] `GET /api/devices` — list with online/offline status +- [ ] `POST /api/send {"to":"name","text":"...","palette":"rainbow"}` — publishes to `[PREFIX]/notify` +- [ ] `POST /api/broadcast {"text":"..."}` — sends to all online device prefixes +- [ ] `GET /api/messages` — recent message history from InfluxDB +- [ ] `GET /sse/devices` — Server-Sent Events for live presence changes +- [ ] `GET /sse/messages` — SSE for live message feed +- [ ] **Friendster UI** — dark-themed buddy list + send form + SSE-driven updates + +### Phase S2 — CueMaster + +- [ ] Saved cues stored in YAML/JSON config file + - Schema: `{name, text, color/palette, targets[], duration}` +- [ ] Target groups (ALL, stage, foh, etc.) +- [ ] `POST /api/cue` — create/save named cue +- [ ] `GET /api/cues` — list saved cues +- [ ] `POST /api/cue/:name/fire` — fire a named cue +- [ ] **CueMaster UI** — device grid, large tap targets, quick-fire buttons, log panel +- [ ] Keyboard shortcuts (1-9 for quick cues, tablet-optimized) + +### Phase S3 — Integration + +- [ ] OSC receive (UDP) — `/friendster/cue/` fires named cue; allows QLab trigger +- [ ] Set Schedule hook — auto-fire cue on scene advance events from `dpx_showsite_ops` +- [ ] HTTP callback API — external systems can fire cues via REST +- [ ] Multi-site support — multiple broker connections + +### Phase S4 — Social Polish + +- [ ] Mobile-optimized Friendster UI +- [ ] PWA manifest + offline support +- [ ] Message reactions +- [ ] Presence icons / avatars per device + +--- + +## /ctrl Page Status (audit 2026-07-18) + +| Card | Status | Notes | +|------|--------|-------| +| Notification | ✅ Works | icon/pushIcon parsed but not rendered (Phase 2); overlays now functional | +| Custom App | ✅ Works | same icon note; deleteCustomApp fixed | +| Indicators | 🟡 Partial | `fade` field still ignored in backend handler | +| Moodlight | ✅ Works | — | +| Display | ✅ Works | — | +| App Channels | ✅ Works | — | +| OSC Listeners | ✅ Works | — | +| TC Settings | ✅ Works | — | +| Native Apps | 🟡 Partial | TIM/DAT toggle implemented; TEMP/HUM/BAT rendering not built yet | +| Time | ✅ Works | — | +| Sensors | ✅ Works | — | +| Sound | 🟡 Partial | SOUND/VOL settings keys are cosmetic (passive buzzer = no volume) | + +--- + +## 1 — cpt-city Gradient Integration + +**Status:** ❌ Not started + +**What it is:** +Load gradient palettes from the cpt-city archive (http://soliton.vm.bytemark.co.uk/pub/cpt-city/). +cpt-city `.cpt` files use a simple `x R G B` text format and cover hundreds of named +color gradients (terrain, scientific, artistic). + +**Current state:** +- WLED already has 59 hardcoded gradient palettes in `wled00/palettes.cpp` +- No references to cpt-city anywhere in the codebase +- `dpx_matrix` supports two-color gradient text (`gradient: [c1, c2]` JSON param) but + only for custom app text rendering, not WLED-wide palettes + +**Integration points:** +- `wled00/palettes.cpp` — add parsed cpt-city palettes alongside existing ones +- `wled00/data/cpal/cpal.htm` — existing palette editor; extend to preview cpt-city entries +- `usermods/dpx_matrix/dpx_text.h` — gradient text rendering already accepts color arrays + +**Approach options (choose one):** +- A) Bundle a curated offline set of popular `.cpt` files, converted to WLED palette format at build time +- B) Device fetches `.cpt` files from cpt-city CDN at runtime (requires HTTP client on device) + +--- + +## 2 — Bigtime Animated GIF Playback* + +**Status:** ❌ Stub — web UI tooling only, zero firmware implementation + +**What it is:** +Display 32×8 animated GIFs on the matrix. The AWTRIX convention stores animations as +a horizontal strip of 8×8 frames in a single GIF (e.g., 4 frames = 32×8 px image). + +**Current state:** +- `usermods/dpx_matrix/dpx_html.h` — web UI tab "Bigtime GIFs" (~220 lines): + - Fetches `.gif` filenames from the Blueforcer/AWTRIX3 GitHub repo + - Converts GIF → frame images in-browser + - Uploads to device LittleFS `/ANIMS/` folder +- **Zero firmware code**: no GIF decoder, no frame extraction, no playback loop, no render mode + +**What needs to be built:** +1. GIF decoder library for ESP32/Arduino (e.g., `AnimatedGIF` by Larry Bank — MIT license) +2. Frame extraction: slice 32×8 GIF into 8×8 frames by x-offset +3. Playback engine: frame timing, loop control, frame index state +4. New render mode `TMODE_GIF` in `usermods/dpx_matrix/dpx_apps.h` +5. Integration with custom app system (`icon` field accepting a `.gif` filename) + +**Files to modify:** +- `usermods/dpx_matrix/dpx_apps.h` — add GIF app type + playback state +- `usermods/dpx_matrix/dpx_text.h` — add GIF frame render path +- `usermods/dpx_matrix/dpx_html.h` — already handles upload side + +--- + +## 3 — LaMetric Icons on Matrix* + +**Status:** 🟡 Partial — icon browser + LittleFS download works; no display rendering + +**What it is:** +Fetch a named LaMetric icon (8×8 PNG from `developer.lametric.com`), decode it to +RGB pixels, and render it on the left 8 columns of the matrix alongside scrolling text. + +**Current state:** +- `usermods/dpx_matrix/dpx_html.h` — icon browser (~120 lines): + - Fetches thumbnails from `developer.lametric.com/content/apps/icon_thumbs/{id}_icon_thumb.png` + - Downloads full PNG to device `/ICONS/` LittleFS folder +- App JSON `"icon": "87"` field is parsed and stored +- **Zero firmware rendering**: no PNG decoder, no pixel extraction, icons never appear on display + +**What needs to be built:** +1. PNG decoder for ESP32 — options: + - `PNGdec` library by Larry Bank (MIT, ESP32-compatible) + - Pre-convert PNGs to raw RGB565/RGB888 at download time (browser-side, avoids on-device decode) +2. Icon render function: 8×8 RGB888 → left 8 columns of matrix +3. Text layout adjustment: when icon present, scroll text in columns 9–32 only +4. Wire into `usermods/dpx_matrix/dpx_apps.h` render loop + +**Files to modify:** +- `usermods/dpx_matrix/dpx_apps.h` — icon render call in app draw loop +- `usermods/dpx_matrix/dpx_html.h` — optionally pre-convert PNG→raw at download time +- New file: `usermods/dpx_matrix/dpx_icons.h` — icon load + render functions + +--- + +## 4 — Font Pixels as WLED LED Effects + +**Status:** ❌ Not started — requires architectural change to text renderer + +**What it is:** +Every pixel of every rendered font character behaves like a pixel in a WLED LED strip. +WLED effects (rainbow, sparkle, pulse, fire, etc.) can be applied per-character or +per-glyph, so text itself animates with the full WLED effect engine rather than just +being a static or single-color block. + +**Current architecture problem:** +`usermods/dpx_matrix/dpx_text.h` rasterizes glyphs directly into the final LED pixel +buffer as RGB888 values. There is no intermediate representation — no per-character +bounding boxes, no "which pixels belong to which glyph" metadata. + +**What needs to be built:** +1. **Bounding box tracking** in `dpx_text.h`: during render, record `{x, y, w, h}` for + each character drawn into a `CharBBox[]` array +2. **Per-character effect mask** in `dpx_overlay.h`: given a bounding box, run a WLED + effect only on those pixels (using a local pixel buffer slice) +3. **JSON field** in the custom app schema: e.g., `"textEffect": "rainbow"` per character + fragment in multi-color text arrays, or `"textEffect": "sparkle"` globally +4. **Effect hookup**: map effect names to existing WLED FX functions or re-implement + lightweight versions that work on arbitrary pixel sub-regions + +**Files to modify:** +- `usermods/dpx_matrix/dpx_text.h` — add bbox tracking output +- `usermods/dpx_matrix/dpx_overlay.h` — add per-region effect application +- `usermods/dpx_matrix/dpx_apps.h` — add `textEffect` JSON field + per-char effect dispatch + +--- + +## 5 — Text Overlay Effects* + +**Status:** 🟡 Partial — 5 effects implemented, 5 others unimplemented, 1 name-mismatch bug + +**What it is:** +Pixel-level effects rendered on top of (or composited with) displayed text. +Defined in the spec as 7 weather-themed overlays plus additional effects. + +**Currently implemented** (`usermods/dpx_matrix/dpx_overlay.h`): +- ✅ `rain` — column-based falling pixels +- ✅ `sparkle` — random pixel lighting +- ✅ `twinkle` — blended random pixels +- ✅ `strobe` — full-matrix flash +- ✅ `blink` — full matrix on/off + +**Not implemented (spec-required):** +- ❌ `snow` — slow drifting white pixels, accumulate at bottom +- ❌ `drizzle` — lighter version of rain (fewer, slower drops) +- ❌ `storm` — heavy rain + occasional flash +- ❌ `thunder` — periodic full-screen white flash +- ❌ `frost` — static blue-white pixel scatter over text + +**Bug — name mismatch:** +The effect name strings in `dpxRenderPixelEffect()` (API parser) do not match the +names documented in the web UI JSON schema (`dpx_html.h`). Fix both sides to agree. + +**Files to modify:** +- `usermods/dpx_matrix/dpx_overlay.h` — add 5 missing effects + fix name constants + +--- + +## 6 — Progress Bar* ✅ DONE + +**Status:** ✅ Fully implemented + +**Implementation:** +- `usermods/dpx_matrix/dpx_text.h` — `dpxDrawProgressBar()` function +- `usermods/dpx_matrix/dpx_apps.h` — JSON parsing + render call in app loop +- `usermods/dpx_matrix/dpx_tc.h` — reuses bar for timecode frame-progress display + +**JSON fields:** `progress` (int 0–100, -1 = hidden), `progressC` (fill color), `progressBC` (background color) + +**Behavior:** Renders in the bottom 2 rows of the 8-row matrix, fills left-to-right proportionally. + +--- + +## Implementation Priority (suggested order) + +1. **#5 Overlay effects** — lowest effort, high spec compliance impact; fix the name bug first +2. **#3 LaMetric icons** — browser-side PNG→raw conversion avoids on-device decoder complexity +3. **#2 Animated GIFs** — depends on choosing + integrating a GIF decoder library +4. **#1 cpt-city gradients** — standalone, no dependencies; start with offline bundle approach +5. **#4 Font pixel effects** — most architectural complexity; design the bbox layer carefully diff --git a/usermods/dpx_matrix/dpx_api.h b/usermods/dpx_matrix/dpx_api.h index f18fbb9f1f..6bd0e1299b 100644 --- a/usermods/dpx_matrix/dpx_api.h +++ b/usermods/dpx_matrix/dpx_api.h @@ -96,6 +96,10 @@ static String dpxSettingsJson() { doc[F("UPPERCASE")] = DPX_UPPERCASE; doc[F("Timezone")] = DPX_TIMEZONE; doc[F("MQTT_PREFIX")] = String(mqttDeviceTopic); + doc[F("SOUND")] = true; // TC001 piezo always available + doc[F("VOL")] = 0; // passive piezo — no volume control + doc[F("TIM")] = DPX_SHOW_TIME; + doc[F("DAT")] = DPX_SHOW_DATE; String s; serializeJson(doc, s); return s; } @@ -119,6 +123,8 @@ static void dpxApplySettings(const String& body) { tzset(); dpxMergeDev(("{\"timezone_posix\":\"" + DPX_TIMEZONE + "\"}").c_str()); } + if (doc.containsKey("TIM")) { DPX_SHOW_TIME = doc["TIM"].as(); dpxRebuildLoop(); } + if (doc.containsKey("DAT")) { DPX_SHOW_DATE = doc["DAT"].as(); dpxRebuildLoop(); } } // ── Route registration ──────────────────────────────────────────────────────── @@ -389,32 +395,58 @@ static void dpxRegisterRoutes() { }); // ── RTTTL / Sound — TC001 piezo buzzer on GPIO 15 ──────────────────────── - // POST /api/rtttl body: raw RTTTL string (e.g. "Beep:d=4,o=5,b=200:c,e,g") + // POST /api/rtttl body: raw RTTTL string or "stop" to silence server.on("/api/rtttl", HTTP_POST, [](AsyncWebServerRequest* r) { String body = dpxBody(r); body.trim(); - if (body.length()) { - dpxBuzzerPlay(body.c_str()); - r->send(200, F("application/json"), F("{\"ok\":true}")); + if (!body.length()) { r->send(400, F("text/plain"), F("RTTTL string or 'stop' required")); return; } + if (body.equalsIgnoreCase("stop")) { + dpxBuzzerStop(); } else { - r->send(400, F("text/plain"), F("RTTTL string required")); + dpxBuzzerPlay(body.c_str()); } + r->send(200, F("application/json"), F("{\"ok\":true}")); }); - // POST /api/sound body: JSON {"rtttl":"..."} — compatible with old senders + // POST /api/sound body: JSON {"rtttl":"..."} or {"sound":"filename"} or empty=stop + // sound files are RTTTL text stored in /MELODIES/.txt on LittleFS server.on("/api/sound", HTTP_POST, [](AsyncWebServerRequest* r) { String body = dpxBody(r); body.trim(); - StaticJsonDocument<256> doc; - if (!deserializeJson(doc, body) && doc.containsKey("rtttl")) { - String s = doc["rtttl"].as(); - dpxBuzzerPlay(s.c_str()); + // Empty body or {} = stop + if (!body.length() || body == F("{}")) { + dpxBuzzerStop(); r->send(200, F("application/json"), F("{\"ok\":true}")); - } else if (body.startsWith("Beep") || body.indexOf(':') > 0) { - // Plain RTTTL string passed to /api/sound as well + return; + } + StaticJsonDocument<256> doc; + if (!deserializeJson(doc, body)) { + if (doc.containsKey("rtttl")) { + dpxBuzzerPlay(doc["rtttl"].as()); + r->send(200, F("application/json"), F("{\"ok\":true}")); + return; + } + if (doc.containsKey("sound")) { + // Load RTTTL from /MELODIES/.txt + String path = String(F("/MELODIES/")) + doc["sound"].as() + F(".txt"); + File f = LittleFS.open(path, "r"); + if (f) { + String rtttl = f.readString(); + f.close(); + rtttl.trim(); + dpxBuzzerPlay(rtttl.c_str()); + r->send(200, F("application/json"), F("{\"ok\":true}")); + } else { + r->send(404, F("text/plain"), F("melody file not found")); + } + return; + } + } + // Fallback: treat raw body as RTTTL string + if (body.indexOf(':') > 0) { dpxBuzzerPlay(body.c_str()); r->send(200, F("application/json"), F("{\"ok\":true}")); } else { - r->send(400, F("text/plain"), F("rtttl field required")); + r->send(400, F("text/plain"), F("rtttl or sound field required")); } }); @@ -455,7 +487,8 @@ static void dpxRegisterRoutes() { // ── Transitions list (stub — not implemented) ───────────────────────────── server.on("/api/transitions", HTTP_GET, [](AsyncWebServerRequest* r) { - r->send(200, F("application/json"), F("[]")); + // Transition names (cross-fade is the only supported type currently) + r->send(200, F("application/json"), F("[\"fade\",\"slide\"]")); }); // ── Reboot ──────────────────────────────────────────────────────────────── @@ -469,4 +502,20 @@ static void dpxRegisterRoutes() { delay(200); ESP.restart(); }); + + // ── Sleep (ESP32 deep sleep) ────────────────────────────────────────── + // POST body: {"sleep": N} — sleep N seconds then wake via timer. + // If N is 0 or omitted, sleeps indefinitely (wake on button press only). + server.on("/api/sleep", HTTP_POST, [](AsyncWebServerRequest* r) { + String body = dpxBody(r); + DynamicJsonDocument doc(64); + uint64_t secs = 0; + if (!deserializeJson(doc, body) && doc.containsKey("sleep")) + secs = (uint64_t)doc["sleep"].as(); + r->send(200, F("application/json"), F("{\"ok\":true}")); + delay(200); + if (secs > 0) + esp_sleep_enable_timer_wakeup(secs * 1000000ULL); + esp_deep_sleep_start(); + }); } diff --git a/usermods/dpx_matrix/dpx_apps.h b/usermods/dpx_matrix/dpx_apps.h index 825df8d307..96b55f3196 100644 --- a/usermods/dpx_matrix/dpx_apps.h +++ b/usermods/dpx_matrix/dpx_apps.h @@ -17,6 +17,7 @@ #pragma once #include #include +#include #include #include "dpx_text.h" #include "dpx_persist.h" @@ -49,6 +50,9 @@ struct DpxCustomApp { unsigned long addedMs = 0; // millis() when app was added bool save = false; std::vector drawCmds; + String overlay = ""; // per-app pixel effect name (e.g. "rain", "snow") + String icon = ""; // icon name (no extension, no path) + int pushIcon = 0; // 0=fixed left, 1=scroll+gone, 2=scroll+loop bool valid = false; // false = slot unused @@ -69,7 +73,8 @@ struct DpxCustomApp { struct DpxApp { String name; DpxCustomApp data; - bool isNative = false; // Time, Date, Temp etc. + bool isNative = false; // Time, Date, WLED etc. + bool muted = false; // if true, skipped in rotation }; // ── OSC Listener Registry ───────────────────────────────────────────────────── @@ -80,9 +85,10 @@ struct DpxOscListener { }; // ── Global app state ────────────────────────────────────────────────────────── -static std::vector dpxApps; // ordered app loop -static std::map dpxCustom; // named custom apps -static std::vector dpxOscListeners; +static std::vector dpxApps; // ordered app loop +static std::map dpxCustom; // named custom apps +static std::set dpxHiddenApps; // removed from rotation (incl. natives) +static std::vector dpxOscListeners; static int dpxCurrentApp = 0; // index into dpxApps static bool dpxAutoTrans = true; // auto-advance enabled @@ -133,6 +139,9 @@ static DpxCustomApp dpxParseApp(const char* json) { if (doc.containsKey("progressBC")) app.pbColor = dpxParseColor(doc["progressBC"], 0x1a1a1a); if (doc.containsKey("lifetime")) app.lifetime = doc["lifetime"].as(); if (doc.containsKey("save")) app.save = doc["save"].as(); + if (doc.containsKey("overlay")) { app.overlay = doc["overlay"].as(); app.overlay.toLowerCase(); } + if (doc.containsKey("icon")) app.icon = doc["icon"].as(); + if (doc.containsKey("pushIcon")) app.pushIcon = doc["pushIcon"].as(); app.addedMs = millis(); // Draw commands @@ -168,20 +177,32 @@ static void dpxExecDraw(const std::vector& cmds) { // ── Native app rendering ────────────────────────────────────────────────────── static void dpxRenderNativeTime() { - time_t now; struct tm ti; - time(&now); localtime_r(&now, &ti); + // localTime is WLED's timezone-adjusted Unix epoch. Respect WLED's useAMPM setting. + // Wrong time → set timezone in WLED: Config → Time & NTP → select timezone. char buf[9]; - strftime(buf, sizeof(buf), "%H:%M", &ti); + if (localTime < 100000UL) { + strncpy(buf, "--:--", sizeof(buf)); // NTP not synced yet + } else if (useAMPM) { + // 12h format with AM/PM indicator + uint8_t h = hourFormat12(localTime); + snprintf(buf, sizeof(buf), "%d:%02d%s", h, minute(localTime), + (hour(localTime) < 12) ? "a" : "p"); + } else { + snprintf(buf, sizeof(buf), "%02d:%02d", hour(localTime), minute(localTime)); + } int w = dpxTextPixelWidth(buf); int x = (DPX_MATRIX_W - w) / 2; dpxRenderText(x, DPX_FONT_BASELINE, buf, 0xFFFFFF); } static void dpxRenderNativeDate() { - time_t now; struct tm ti; - time(&now); localtime_r(&now, &ti); char buf[9]; - strftime(buf, sizeof(buf), "%d.%m.%y", &ti); + if (localTime < 100000UL) { + strncpy(buf, "--.--.--", sizeof(buf)); + } else { + snprintf(buf, sizeof(buf), "%02d.%02d.%02d", + day(localTime), month(localTime), year(localTime) % 100); + } int w = dpxTextPixelWidth(buf); int x = (DPX_MATRIX_W - w) / 2; dpxRenderText(x, DPX_FONT_BASELINE, buf, 0x8888FF); @@ -203,7 +224,7 @@ static bool dpxRenderApp(DpxCustomApp& app) { dpxDrawProgressBar(app.progress, app.pColor, app.pbColor); } - int textY = app.topText ? 0 : 1; // text row + int textY = app.topText ? (DPX_FONT_BASELINE - 1) : DPX_FONT_BASELINE; // proper AwtrixFont baselines int textW = dpxTextPixelWidth(app.text.c_str()); if (app.noScroll || textW <= DPX_MATRIX_W) { @@ -225,12 +246,17 @@ static bool dpxRenderApp(DpxCustomApp& app) { // ── App loop management ─────────────────────────────────────────────────────── -// Rebuild dpxApps from dpxCustom (preserves native apps, appends custom ones). +// Rebuild dpxApps from dpxCustom. Any app in dpxHiddenApps is skipped. static void dpxRebuildLoop() { std::vector newList; - // Always-first native apps - { DpxApp a; a.name="Time"; a.isNative=true; newList.push_back(a); } - { DpxApp a; a.name="Date"; a.isNative=true; newList.push_back(a); } + // Native apps — included unless user deleted them from the rotation + const char* natives[] = {"Time", "Date", "WLED"}; + for (auto n : natives) { + if (dpxHiddenApps.find(String(n)) == dpxHiddenApps.end()) { + DpxApp a; a.name = n; a.isNative = true; + newList.push_back(a); + } + } // Custom apps in insertion order for (auto& kv : dpxCustom) { if (kv.second.valid) { @@ -245,30 +271,47 @@ static void dpxRebuildLoop() { if (dpxCurrentApp >= (int)dpxApps.size()) dpxCurrentApp = 0; } -// Add or update a custom app by name. Empty body = delete. +// Add or update a custom app. Empty body = remove from rotation. +// Native apps (Time, Date, WLED) are hidden (not deleted); custom apps are erased. static void dpxSetCustomApp(const String& name, const char* json) { if (!json || strlen(json) <= 2) { - // Empty JSON or null → delete + // Remove from rotation — custom erased, natives hidden dpxCustom.erase(name); + dpxHiddenApps.insert(name); + LittleFS.remove("/CUSTOMAPPS/" + name + ".json"); } else { DpxCustomApp app = dpxParseApp(json); - if (app.valid) dpxCustom[name] = app; + if (app.valid) { + dpxCustom[name] = app; + dpxHiddenApps.erase(name); // restore if previously removed + if (app.save) { + LittleFS.mkdir("/CUSTOMAPPS"); + File f = LittleFS.open("/CUSTOMAPPS/" + name + ".json", "w"); + if (f) { f.print(json); f.close(); } + } + } } dpxRebuildLoop(); } -// Advance to next app +// Advance to next unmuted app static void dpxNextApp() { if (dpxApps.empty()) return; - dpxCurrentApp = (dpxCurrentApp + 1) % dpxApps.size(); + int start = dpxCurrentApp; + do { + dpxCurrentApp = (dpxCurrentApp + 1) % dpxApps.size(); + } while (dpxApps[dpxCurrentApp].muted && dpxCurrentApp != start); dpxAppStartMs = millis(); dpxScroll.stop(); } -// Go to previous app +// Go to previous unmuted app static void dpxPrevApp() { if (dpxApps.empty()) return; - dpxCurrentApp = (dpxCurrentApp + (int)dpxApps.size() - 1) % dpxApps.size(); + int start = dpxCurrentApp; + do { + dpxCurrentApp = (dpxCurrentApp + (int)dpxApps.size() - 1) % dpxApps.size(); + } while (dpxApps[dpxCurrentApp].muted && dpxCurrentApp != start); dpxAppStartMs = millis(); dpxScroll.stop(); } @@ -304,12 +347,21 @@ static String dpxGetAppsJson() { JsonArray arr = doc.to(); for (auto& a : dpxApps) { JsonObject o = arr.createNestedObject(); - o["name"] = a.name; + o["name"] = a.name; o["native"] = a.isNative; + o["muted"] = a.muted; } String s; serializeJson(doc, s); return s; } +// Mute or unmute an app by name. Returns false if name not found. +static bool dpxMuteApp(const String& name, bool mute) { + for (auto& a : dpxApps) { + if (a.name == name) { a.muted = mute; return true; } + } + return false; +} + // Return JSON of a specific custom app's current state static String dpxGetCustomAppJson(const String& name) { if (dpxCustom.find(name) == dpxCustom.end()) return F("{}"); @@ -324,6 +376,9 @@ static String dpxGetCustomAppJson(const String& name) { doc["scrollSpeed"] = a.scrollSpeed; doc["duration"] = a.duration; doc["progress"] = a.progress; + doc["icon"] = a.icon; + doc["pushIcon"] = a.pushIcon; + doc["overlay"] = a.overlay; String s; serializeJson(doc, s); return s; } @@ -347,7 +402,7 @@ static void dpxAppLoopTick() { : dpxApps[dpxCurrentApp].data.durationMs(); if (now - dpxAppStartMs >= dur) { - dpxNextApp(); + dpxNextApp(); // dpxNextApp already skips muted apps } } @@ -362,6 +417,7 @@ static void dpxRenderCurrentApp() { DpxApp& app = dpxApps[dpxCurrentApp]; if (app.isNative) { + if (app.name == "WLED") return; // passthrough — WLED effect renders unobstructed dpxClear(); if (app.name == "Time") dpxRenderNativeTime(); else if (app.name == "Date") dpxRenderNativeDate(); diff --git a/usermods/dpx_matrix/dpx_firstboot.h b/usermods/dpx_matrix/dpx_firstboot.h index aea4503544..c9a0439f41 100644 --- a/usermods/dpx_matrix/dpx_firstboot.h +++ b/usermods/dpx_matrix/dpx_firstboot.h @@ -73,7 +73,7 @@ static void dpxFirstBoot() { panel["b"] = false; // top start panel["r"] = false; // left start panel["v"] = false; // horizontal - panel["s"] = false; // serpentine — set true in WLED UI if needed + panel["s"] = true; // TC001 is serpentine-wired panel["x"] = 0; panel["y"] = 0; panel["h"] = 8; @@ -98,6 +98,11 @@ static void dpxFirstBoot() { doc["ota"]["lock"] = false; + // Enable NTP — time sync is needed for Time/Date apps + doc["if"]["ntp"]["en"] = true; + doc["if"]["ntp"]["host"] = "pool.ntp.org"; + doc["if"]["ntp"]["tz"] = 0; // UTC; user sets timezone in WLED → Config → Time + File f = LittleFS.open(F("/cfg.json"), "w"); if (!f) { DEBUG_PRINTLN(F("DpxMatrix: failed to open /cfg.json")); return; } serializeJson(doc, f); diff --git a/usermods/dpx_matrix/dpx_html.h b/usermods/dpx_matrix/dpx_html.h index 6b32a9c04a..140ba7c5ce 100644 --- a/usermods/dpx_matrix/dpx_html.h +++ b/usermods/dpx_matrix/dpx_html.h @@ -656,7 +656,7 @@ select option{background:#222}
    -
    +
    @@ -711,7 +711,7 @@ select option{background:#222}
    -
    +
    @@ -1019,7 +1019,7 @@ select option{background:#222}

    Sound

    -
    +
    Volume: n/a — passive piezo

    @@ -1040,7 +1040,7 @@ select option{background:#222}
    - +

    @@ -1151,12 +1151,7 @@ function deleteCustomApp(){ var name=document.getElementById("ca_name").value;if(!name){toast("Name required",false);return;} fetch("/api/custom?name="+encodeURIComponent(name),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:""})}).then(function(){ toast("App removed"); - // Force loop refresh so the slot is cleared immediately - fetch("/api/loop").then(function(r){return r.json();}).then(function(apps){ - var names=apps.filter(function(a){return a.name!==name;}).map(function(a){return a.name;}); - fetch("/api/apps",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(names)}); - setTimeout(loadLoop,600); - }); + setTimeout(loadLoop,600); }); } function sendInd(n){ @@ -1223,7 +1218,7 @@ function switchApp(){ } function sendRtttl(){ var v=document.getElementById("rtttl").value;if(!v){toast("Enter RTTTL string",false);return;} - fetch("/api/rtttl",{method:"POST",body:v}).then(function(r){r.ok?toast("Playing"):toast("Error "+r.status,false);}); + fetch("/api/rtttl",{method:"POST",headers:{"Content-Type":"text/plain"},body:v}).then(function(r){r.ok?toast("Playing ♪"):toast("Error "+r.status,false);}); } function sendSound(){ var v=document.getElementById("snd_file").value;if(!v){toast("Enter filename",false);return;} diff --git a/usermods/dpx_matrix/dpx_matrix.h b/usermods/dpx_matrix/dpx_matrix.h index b502772545..03ea230922 100644 --- a/usermods/dpx_matrix/dpx_matrix.h +++ b/usermods/dpx_matrix/dpx_matrix.h @@ -42,31 +42,7 @@ class DpxMatrix : public Usermod { private: bool _initDone = false; - - // ── Button debounce state ─────────────────────────────────────────────── - // Buttons are active-LOW (internal pull-up). We fire on falling edge. - struct BtnState { - uint8_t pin; - bool lastRaw = true; // last raw read (true = not pressed) - bool debounced = true; // debounced state - uint32_t lastMs = 0; - }; - BtnState _btn[3]; // index 0=left, 1=mid, 2=right - - // Poll one button; returns true on falling-edge (press event). - bool _pollBtn(BtnState& b) { - if (b.pin == 255) return false; - bool raw = digitalRead(b.pin); - uint32_t now = millis(); - if (raw != b.lastRaw) b.lastMs = now; // reset timer on any change - b.lastRaw = raw; - if ((now - b.lastMs) >= 50) { // 50 ms debounce - bool prev = b.debounced; - b.debounced = raw; - if (prev && !raw) return true; // falling edge = press - } - return false; - } + bool dpxEnabled = true; // Render the 3 indicator pixels (corner dots). // Indicator 1 = top-left (pixel 0) @@ -94,16 +70,6 @@ class DpxMatrix : public Usermod { dpxRebuildLoop(); dpxAppStartMs = millis(); - // Initialise button pins (active-low, internal pull-up) - const uint8_t btnPins[3] = { DPX_BTN_LEFT, DPX_BTN_MID, DPX_BTN_RIGHT }; - for (int i = 0; i < 3; i++) { - _btn[i].pin = btnPins[i]; - _btn[i].lastRaw = true; - _btn[i].debounced = true; - _btn[i].lastMs = 0; - if (_btn[i].pin != 255) pinMode(_btn[i].pin, INPUT_PULLUP); - } - // Initialise TC001 buzzer pin; drives LOW to prevent float noise. dpxBuzzerInit(); @@ -160,7 +126,47 @@ class DpxMatrix : public Usermod { if (now - _lastLoopMs < 20) return; _lastLoopMs = now; - // Reprint IP whenever serial is freshly connected + // ── Serial debug command handler ──────────────────────────────── + // Send a character to get status info. Commands: + // ? / h — help + // s — status (IP, app, time, RSSI, heap) + // r — reboot + if (Serial.available()) { + char cmd = Serial.read(); + while (Serial.available()) Serial.read(); // flush + switch (cmd) { + case '?': case 'h': + Serial.println(F("[dpx] commands: s=status r=reboot h=help")); + break; + case 's': { + Serial.printf("[dpx] IP : %s\n", WiFi.localIP().toString().c_str()); + Serial.printf("[dpx] AP SSID : %s (%s) clients=%d\n", + apSSID, + WiFi.softAPIP().toString().c_str(), + WiFi.softAPgetStationNum()); + Serial.printf("[dpx] WiFi : %s (RSSI %d dBm)\n", + WiFi.SSID().c_str(), WiFi.RSSI()); + Serial.printf("[dpx] Heap : %u free / %u total\n", + ESP.getFreeHeap(), ESP.getHeapSize()); + Serial.printf("[dpx] App : %s (#%u of %u)\n", + dpxCurrentApp < dpxApps.size() ? dpxApps[dpxCurrentApp].name.c_str() : "?", + (unsigned)dpxCurrentApp, (unsigned)dpxApps.size()); + Serial.printf("[dpx] Notifs : %u queued\n", (unsigned)dpxNotifQueue.size()); + Serial.printf("[dpx] Time : %02d:%02d:%02d (localTime=%lu)\n", + hour(localTime), minute(localTime), second(localTime), (unsigned long)localTime); + Serial.printf("[dpx] Uptime : %lus\n", millis() / 1000); + Serial.printf("[dpx] MQTT : %s\n", WLED_MQTT_CONNECTED ? "connected" : "disconnected"); + Serial.printf("[dpx] OSC UDP : %s port %d\n", dpxUdpStarted ? "started" : "stopped", DPX_OSC_PORT); + break; + } + case 'r': + Serial.println(F("[dpx] rebooting...")); + delay(100); ESP.restart(); + break; + default: + Serial.printf("[dpx] unknown command '%c' — send h for help\n", cmd); + } + } static bool _serialWasConnected = false; bool serialNow = (bool)Serial; if (serialNow && !_serialWasConnected && WiFi.localIP()[0] != 0) { @@ -186,15 +192,64 @@ class DpxMatrix : public Usermod { // Advance RTTTL note sequencer dpxBuzzerTick(); + } + + // ── Button handling ──────────────────────────────────────────────────── + // Called by WLED's button loop on every tick for each configured button. + // Returning true consumes the event — WLED will not act on it. + // We use WLED's APIs (toggleOnOff, stateUpdated) for WLED-level actions. + // + // Button layout (TC001 front, left→right): + // b=0 GPIO DPX_BTN_LEFT short=prev app long=dismiss notification + // b=1 GPIO DPX_BTN_MID short=next app long=cycle WLED effect + // b=2 GPIO DPX_BTN_RIGHT short=power tog long=show IP + bool handleButton(uint8_t b) override { + if (!_initDone || b > 2) return false; + + static const uint8_t PINS[3] = {DPX_BTN_LEFT, DPX_BTN_MID, DPX_BTN_RIGHT}; + static unsigned long pressStart[3] = {0, 0, 0}; + static bool wasPressed[3] = {false, false, false}; + + bool pressed = (digitalRead(PINS[b]) == LOW); // active-low + unsigned long now = millis(); - // Physical buttons - // LEFT → previous app, RIGHT → next app, MIDDLE → toggle dpxEnabled - if (_pollBtn(_btn[0])) dpxPrevApp(); - if (_pollBtn(_btn[2])) dpxNextApp(); - if (_pollBtn(_btn[1])) { - dpxEnabled = !dpxEnabled; - DEBUG_PRINTF("DpxMatrix: button toggle enabled=%d\n", (int)dpxEnabled); + if (pressed && !wasPressed[b]) { + pressStart[b] = now; // rising edge + } else if (!pressed && wasPressed[b]) { + // falling edge — determine action + unsigned long dur = now - pressStart[b]; + if (dur >= 30) { // debounce threshold + bool lng = (dur > 800); + switch (b) { + case 0: // LEFT + lng ? dpxDismissNotification() : dpxPrevApp(); + break; + case 1: // MIDDLE — next app / long=cycle effect + if (lng) { + effectCurrent = (effectCurrent + 1) % strip.getModeCount(); + stateChanged = true; + colorUpdated(CALL_MODE_BUTTON); + } else { + dpxNextApp(); + } + break; + case 2: // RIGHT — power toggle / long=show IP + if (lng) { + String ip = WiFi.localIP().toString(); + StaticJsonDocument<64> doc; + doc["text"] = ip; doc["color"] = "#00FF88"; + String s; serializeJson(doc, s); + dpxPushNotification(s.c_str()); + } else { + toggleOnOff(); + stateUpdated(CALL_MODE_BUTTON); + } + break; + } + } } + wasPressed[b] = pressed; + return true; // always consume — prevent WLED double-acting on these pins } void handleOverlayDraw() override { @@ -208,6 +263,26 @@ class DpxMatrix : public Usermod { } // Pixel effects + text overlay on top of app content + // Per-app overlay: activate the pixel effect requested by the current + // app or notification. Resets when the displayed item changes. + { + String wantEffect; + if (dpxNotifActive && dpxCurrentNotif.data.valid) + wantEffect = dpxCurrentNotif.data.overlay; + else if (!dpxApps.empty() && !dpxApps[dpxCurrentApp].isNative) + wantEffect = dpxApps[dpxCurrentApp].data.overlay; + + static String _prevAppEffect; + if (wantEffect != _prevAppEffect) { + _prevAppEffect = wantEffect; + if (wantEffect.length() && wantEffect != "none") { + String j = String("{\"name\":\"") + wantEffect + "\",\"intensity\":60}"; + dpxSetPixelEffect(j.c_str()); + } else { + dpxClearPixelEffect(); + } + } + } dpxRenderOverlays(); // Indicator corner dots (topmost layer) @@ -243,6 +318,13 @@ class DpxMatrix : public Usermod { if (tc.length() >= 8) dpxPushTC(tc); } + // Mute/unmute channels: {"mute": {"Time": true, "WLED": false}} + if (dpx.containsKey(F("mute"))) { + JsonObject mutes = dpx[F("mute")].as(); + for (JsonPair kv : mutes) + dpxMuteApp(String(kv.key().c_str()), kv.value().as()); + } + // Enable/disable matrix overlay if (dpx.containsKey(F("enabled"))) dpxEnabled = dpx[F("enabled")].as(); diff --git a/usermods/dpx_matrix/dpx_mqtt.h b/usermods/dpx_matrix/dpx_mqtt.h index dbc3a710cb..daac689776 100644 --- a/usermods/dpx_matrix/dpx_mqtt.h +++ b/usermods/dpx_matrix/dpx_mqtt.h @@ -184,6 +184,16 @@ static bool dpxMqttMessage(char* topic, char* payload) { return true; } + // ── Channel mute ────────────────────────────────────────────────────────── + // topic: .../dpx/mute/ payload: 1/0/true/false/on/off + if (cmd.startsWith(F("mute/"))) { + String name = cmd.substring(5); + String p(payload); p.trim(); p.toLowerCase(); + bool mute = (p == "1" || p == "true" || p == "on"); + dpxMuteApp(name, mute); + return true; + } + // ── Text overlay ────────────────────────────────────────────────────────── if (cmd == F("overlay")) { String p(payload); p.trim(); diff --git a/usermods/dpx_matrix/dpx_overlay.h b/usermods/dpx_matrix/dpx_overlay.h index 2e1bf76457..3e94a7e384 100644 --- a/usermods/dpx_matrix/dpx_overlay.h +++ b/usermods/dpx_matrix/dpx_overlay.h @@ -62,7 +62,10 @@ static struct { // per-effect private state unsigned long lastMs = 0; bool strobeOn = true; - uint8_t rain[DPX_MATRIX_W] = {}; // rain column heights + uint8_t rain[DPX_MATRIX_W] = {}; // rain/drizzle/storm drop positions per column + uint8_t snow[DPX_MATRIX_W] = {}; // snow floor accumulation (rows from bottom) + bool frostInit = false; // frost: static pattern generated? + uint8_t frost[256] = {}; // frost: which pixels are frosted (1=yes) } dpxPixelEffect; // ── Text overlay control ────────────────────────────────────────────────────── @@ -149,7 +152,9 @@ static bool dpxSetPixelEffect(const char* json) { dpxPixelEffect.active = (name != "none" && name.length() > 0); dpxPixelEffect.lastMs = 0; dpxPixelEffect.strobeOn = true; - memset(dpxPixelEffect.rain, 0, sizeof(dpxPixelEffect.rain)); + memset(dpxPixelEffect.rain, 0, sizeof(dpxPixelEffect.rain)); + memset(dpxPixelEffect.snow, 0, sizeof(dpxPixelEffect.snow)); + dpxPixelEffect.frostInit = false; return true; } @@ -233,6 +238,124 @@ static void dpxRenderPixelEffect() { } } } + + // ── Drizzle: lighter rain \u2014 fewer, slower, dimmer drops ────────────────── + else if (dpxPixelEffect.name == "drizzle") { + int intervalMs = map(iv, 0, 100, 400, 80); + if (now - dpxPixelEffect.lastMs >= (unsigned long)intervalMs) { + dpxPixelEffect.lastMs = now; + for (int x = 0; x < DPX_MATRIX_W; x++) { + if (dpxPixelEffect.rain[x] > 0) { + int y = dpxPixelEffect.rain[x] - 1; + if (y < DPX_MATRIX_H) dpxSetPixel(x, y, 0); + dpxPixelEffect.rain[x]++; + if ((int)dpxPixelEffect.rain[x] - 1 < DPX_MATRIX_H) + dpxSetPixel(x, dpxPixelEffect.rain[x] - 1, 0x4466AA); + if ((int)dpxPixelEffect.rain[x] > DPX_MATRIX_H + 1) + dpxPixelEffect.rain[x] = 0; + } + if (dpxPixelEffect.rain[x] == 0 && (random(512) < (uint32_t)(iv + 5))) + dpxPixelEffect.rain[x] = 1; + } + } + } + + // ── Storm: heavy rain + occasional lightning flash ──────────────────── + else if (dpxPixelEffect.name == "storm") { + int intervalMs = map(iv, 0, 100, 100, 10); + if (now - dpxPixelEffect.lastMs >= (unsigned long)intervalMs) { + dpxPixelEffect.lastMs = now; + for (int x = 0; x < DPX_MATRIX_W; x++) { + if (dpxPixelEffect.rain[x] > 0) { + int y = dpxPixelEffect.rain[x] - 1; + if (y < DPX_MATRIX_H) dpxSetPixel(x, y, 0); + dpxPixelEffect.rain[x]++; + if ((int)dpxPixelEffect.rain[x] - 1 < DPX_MATRIX_H) + dpxSetPixel(x, dpxPixelEffect.rain[x] - 1, 0x4466FF); + if ((int)dpxPixelEffect.rain[x] > DPX_MATRIX_H + 1) + dpxPixelEffect.rain[x] = 0; + } + if (dpxPixelEffect.rain[x] == 0 && (random(128) < (uint32_t)(iv * 3 + 20))) + dpxPixelEffect.rain[x] = 1; + } + } + // Occasional lightning flash (2 bright frames) + static unsigned long _stormFlashMs = 0; + static int _stormFlashFrames = 0; + if (_stormFlashFrames > 0) { + for (int i = 0; i < 256; i++) + strip.setPixelColor(i, color_blend(strip.getPixelColor(i), 0xFFFFFF, 180)); + _stormFlashFrames--; + } else if (now - _stormFlashMs > 2000 && random(200) < 5) { + _stormFlashMs = now; + _stormFlashFrames = 2; + } + } + + // ── Thunder: periodic full-screen white flash, no rain ─────────────── + else if (dpxPixelEffect.name == "thunder") { + // intervalMs decreases with intensity (more frequent flashes) + int intervalMs = map(iv, 0, 100, 4000, 600); + if (now - dpxPixelEffect.lastMs >= (unsigned long)intervalMs) { + dpxPixelEffect.lastMs = now; + dpxPixelEffect.strobeOn = true; + } + if (dpxPixelEffect.strobeOn) { + for (int i = 0; i < 256; i++) + strip.setPixelColor(i, color_blend(strip.getPixelColor(i), 0xFFFFFF, 220)); + dpxPixelEffect.strobeOn = false; // single frame flash + } + } + + // ── Snow: slow-falling white flakes, accumulate at the bottom ───────── + else if (dpxPixelEffect.name == "snow") { + int intervalMs = map(iv, 0, 100, 350, 70); + if (now - dpxPixelEffect.lastMs >= (unsigned long)intervalMs) { + dpxPixelEffect.lastMs = now; + for (int x = 0; x < DPX_MATRIX_W; x++) { + if (dpxPixelEffect.rain[x] > 0) { + int y = dpxPixelEffect.rain[x] - 1; + // floor = bottom of free space above snow pile + int floorY = DPX_MATRIX_H - 1 - (int)dpxPixelEffect.snow[x]; + if (y >= floorY) { + // Flake landed \u2014 grow pile + if (dpxPixelEffect.snow[x] < DPX_MATRIX_H) + dpxPixelEffect.snow[x]++; + dpxPixelEffect.rain[x] = 0; + } else { + if (y < DPX_MATRIX_H) dpxSetPixel(x, y, 0); + dpxPixelEffect.rain[x]++; + if ((int)dpxPixelEffect.rain[x] - 1 < DPX_MATRIX_H) + dpxSetPixel(x, dpxPixelEffect.rain[x] - 1, 0xDDDDFF); + } + } else if (random(1024) < (uint32_t)(iv + 5)) { + dpxPixelEffect.rain[x] = 1; + } + } + // Redraw snow floor every tick + for (int x = 0; x < DPX_MATRIX_W; x++) { + for (uint8_t py = 0; py < dpxPixelEffect.snow[x]; py++) { + dpxSetPixel(x, DPX_MATRIX_H - 1 - py, 0xDDDDFF); + } + } + } + } + + // ── Frost: static blue-white scatter generated once per activation ──── + else if (dpxPixelEffect.name == "frost") { + if (!dpxPixelEffect.frostInit) { + // Generate pattern once: ~(intensity/2)% of pixels frosted + dpxPixelEffect.frostInit = true; + int count = (256 * iv) / 200; + memset(dpxPixelEffect.frost, 0, sizeof(dpxPixelEffect.frost)); + for (int i = 0; i < count; i++) + dpxPixelEffect.frost[(int)random(256)] = 1; + } + for (int i = 0; i < 256; i++) { + if (dpxPixelEffect.frost[i]) + strip.setPixelColor(i, color_blend(strip.getPixelColor(i), 0xAADDFF, 160)); + } + } } // ── Master overlay render — call at end of handleOverlayDraw() ──────────────── diff --git a/usermods/dpx_matrix/dpx_persist.h b/usermods/dpx_matrix/dpx_persist.h index 298160c081..c3538ffe17 100644 --- a/usermods/dpx_matrix/dpx_persist.h +++ b/usermods/dpx_matrix/dpx_persist.h @@ -41,6 +41,9 @@ static int DPX_SSPEED = 100; // global scroll speed % static bool DPX_UPPERCASE = true; // force uppercase text static bool dpxEnabled = true; // false = pass-through to WLED effects static String DPX_TIMEZONE; // POSIX TZ string (e.g. PST8PDT,...) +// Native app visibility (toggled via POST /api/settings TIM/DAT keys) +static bool DPX_SHOW_TIME = true; +static bool DPX_SHOW_DATE = false; // ── Load dev.json from LittleFS ─────────────────────────────────────────────── static void dpxLoadDev() { From a513105beb9cc606a1756f7c35a63ae9ef29cbc1 Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 18 Jul 2026 14:11:06 -0400 Subject: [PATCH 6/9] fix: NTP always-on; DNA spiral default; power fade restored; time/date cleanup - WLED_NTP_ENABLED=true in platformio_override.ini (default was false) - NTP status added to serial 's' debug dump - DNA Spiral (effect 182) set as default startup effect in firstboot - Removed transition=0 from firstboot so power fade works again - Time/Date render: snapshot localTime; leftover fragment removed - Reverted forced ntpEnabled override (not needed with compile flag) --- platformio_override.ini | 1 + usermods/dpx_matrix/dpx_apps.h | 21 ++++++++++----------- usermods/dpx_matrix/dpx_firstboot.h | 9 +++++---- usermods/dpx_matrix/dpx_matrix.h | 4 ++++ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/platformio_override.ini b/platformio_override.ini index bc36e61793..983fb51343 100644 --- a/platformio_override.ini +++ b/platformio_override.ini @@ -35,6 +35,7 @@ build_flags = -D DPX_BTN_MID=14 -D DPX_BTN_RIGHT=27 -D WLED_USE_LITTLEFS + -D WLED_NTP_ENABLED=true -D WLED_VERSION='"dpx_tc002-dev"' -D WLED_PRODUCT_NAME='"dpx_tc002"' -D WLED_INSTANCE_NAME='"dpx_tc002"' diff --git a/usermods/dpx_matrix/dpx_apps.h b/usermods/dpx_matrix/dpx_apps.h index 96b55f3196..467e15dd36 100644 --- a/usermods/dpx_matrix/dpx_apps.h +++ b/usermods/dpx_matrix/dpx_apps.h @@ -177,18 +177,16 @@ static void dpxExecDraw(const std::vector& cmds) { // ── Native app rendering ────────────────────────────────────────────────────── static void dpxRenderNativeTime() { - // localTime is WLED's timezone-adjusted Unix epoch. Respect WLED's useAMPM setting. - // Wrong time → set timezone in WLED: Config → Time & NTP → select timezone. + // Snapshot localTime once to avoid reading a partially-updated value mid-render. + time_t t = localTime; char buf[9]; - if (localTime < 100000UL) { - strncpy(buf, "--:--", sizeof(buf)); // NTP not synced yet + if (t < 100000UL) { + strncpy(buf, "--:--", sizeof(buf)); } else if (useAMPM) { - // 12h format with AM/PM indicator - uint8_t h = hourFormat12(localTime); - snprintf(buf, sizeof(buf), "%d:%02d%s", h, minute(localTime), - (hour(localTime) < 12) ? "a" : "p"); + snprintf(buf, sizeof(buf), "%d:%02d%s", + hourFormat12(t), minute(t), (hour(t) < 12) ? "a" : "p"); } else { - snprintf(buf, sizeof(buf), "%02d:%02d", hour(localTime), minute(localTime)); + snprintf(buf, sizeof(buf), "%02d:%02d", hour(t), minute(t)); } int w = dpxTextPixelWidth(buf); int x = (DPX_MATRIX_W - w) / 2; @@ -196,12 +194,13 @@ static void dpxRenderNativeTime() { } static void dpxRenderNativeDate() { + time_t t = localTime; char buf[9]; - if (localTime < 100000UL) { + if (t < 100000UL) { strncpy(buf, "--.--.--", sizeof(buf)); } else { snprintf(buf, sizeof(buf), "%02d.%02d.%02d", - day(localTime), month(localTime), year(localTime) % 100); + day(t), month(t), year(t) % 100); } int w = dpxTextPixelWidth(buf); int x = (DPX_MATRIX_W - w) / 2; diff --git a/usermods/dpx_matrix/dpx_firstboot.h b/usermods/dpx_matrix/dpx_firstboot.h index c9a0439f41..cd90213f29 100644 --- a/usermods/dpx_matrix/dpx_firstboot.h +++ b/usermods/dpx_matrix/dpx_firstboot.h @@ -87,14 +87,15 @@ static void dpxFirstBoot() { JsonObject b1 = btn["ins"].createNestedObject(); b1["type"]=2; b1["pin"][0]=14; b1["macros"][0]=0; b1["macros"][1]=0; b1["macros"][2]=0; JsonObject b2 = btn["ins"].createNestedObject(); b2["type"]=2; b2["pin"][0]=27; b2["macros"][0]=0; b2["macros"][1]=0; b2["macros"][2]=0; - // Light — instant transitions - doc["light"]["tr"]["dur"] = 0; - doc["light"]["tr"]["rpc"] = 5; + // Light — keep WLED's default transition (750ms) so power fade works + // Do NOT set dur=0 here; that kills the power-on/off fade animation. + // Users can reduce transition in WLED → LED Preferences if desired. - // Defaults + // Defaults — DNA Spiral as startup effect (FX_MODE_2DDNASPIRAL = 182) doc["def"]["ps"] = 0; doc["def"]["on"] = true; doc["def"]["bri"] = 128; + doc["def"]["fx"] = 182; // 2D DNA Spiral — works great on 32×8 matrix doc["ota"]["lock"] = false; diff --git a/usermods/dpx_matrix/dpx_matrix.h b/usermods/dpx_matrix/dpx_matrix.h index 03ea230922..d1c13ddba6 100644 --- a/usermods/dpx_matrix/dpx_matrix.h +++ b/usermods/dpx_matrix/dpx_matrix.h @@ -152,6 +152,10 @@ class DpxMatrix : public Usermod { dpxCurrentApp < dpxApps.size() ? dpxApps[dpxCurrentApp].name.c_str() : "?", (unsigned)dpxCurrentApp, (unsigned)dpxApps.size()); Serial.printf("[dpx] Notifs : %u queued\n", (unsigned)dpxNotifQueue.size()); + Serial.printf("[dpx] NTP : enabled=%s synced=%s server=%s\n", + ntpEnabled ? "YES" : "NO", + (localTime > 100000UL) ? "YES" : "NO", + ntpServerName); Serial.printf("[dpx] Time : %02d:%02d:%02d (localTime=%lu)\n", hour(localTime), minute(localTime), second(localTime), (unsigned long)localTime); Serial.printf("[dpx] Uptime : %lus\n", millis() / 1000); From 20b0b8fc9000c39a237484c06faee217734405d2 Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 18 Jul 2026 14:20:47 -0400 Subject: [PATCH 7/9] chore: final pre-merge cleanup --- docs/ROADMAP.md | 6 ++++++ usermods/dpx_matrix/dpx_apps.h | 21 +++++++++++---------- usermods/dpx_matrix/dpx_matrix.h | 4 ---- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 83c4517d4b..648029df0c 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -31,6 +31,12 @@ See Part 2 of this file. - [x] **1.7** `/api/sleep` not implemented — added ESP32 deep sleep with optional timer wakeup (`{"sleep":N}`) - [x] **1.8** `save` flag — `save: true` in custom app JSON now persists to `/CUSTOMAPPS/.json` on LittleFS; delete also removes the file - [x] **1.9** Per-app overlay activation — added hook in `handleOverlayDraw()` in `dpx_matrix.h`; overlay activates automatically when app/notification is shown, clears on transition +- [ ] **1.10** Serial config dump `dpx_matrix.h` + - Add `c` command to the serial debug handler that dumps key LittleFS config files to serial + - Print `/dev.json`, `/cfg.json` (WLED wifi/mqtt config), `/osc_listeners.json` — pretty-printed with section headers + - Format: `─── /dev.json ───` header, then indented JSON, then a separator line + - Also print active runtime globals (DPX_TIMEZONE, DPX_ATIME, DPX_SHOW_TIME, etc.) below the raw file + - Update help string: `s=status c=config dump r=reboot h=help` --- diff --git a/usermods/dpx_matrix/dpx_apps.h b/usermods/dpx_matrix/dpx_apps.h index 467e15dd36..96b55f3196 100644 --- a/usermods/dpx_matrix/dpx_apps.h +++ b/usermods/dpx_matrix/dpx_apps.h @@ -177,16 +177,18 @@ static void dpxExecDraw(const std::vector& cmds) { // ── Native app rendering ────────────────────────────────────────────────────── static void dpxRenderNativeTime() { - // Snapshot localTime once to avoid reading a partially-updated value mid-render. - time_t t = localTime; + // localTime is WLED's timezone-adjusted Unix epoch. Respect WLED's useAMPM setting. + // Wrong time → set timezone in WLED: Config → Time & NTP → select timezone. char buf[9]; - if (t < 100000UL) { - strncpy(buf, "--:--", sizeof(buf)); + if (localTime < 100000UL) { + strncpy(buf, "--:--", sizeof(buf)); // NTP not synced yet } else if (useAMPM) { - snprintf(buf, sizeof(buf), "%d:%02d%s", - hourFormat12(t), minute(t), (hour(t) < 12) ? "a" : "p"); + // 12h format with AM/PM indicator + uint8_t h = hourFormat12(localTime); + snprintf(buf, sizeof(buf), "%d:%02d%s", h, minute(localTime), + (hour(localTime) < 12) ? "a" : "p"); } else { - snprintf(buf, sizeof(buf), "%02d:%02d", hour(t), minute(t)); + snprintf(buf, sizeof(buf), "%02d:%02d", hour(localTime), minute(localTime)); } int w = dpxTextPixelWidth(buf); int x = (DPX_MATRIX_W - w) / 2; @@ -194,13 +196,12 @@ static void dpxRenderNativeTime() { } static void dpxRenderNativeDate() { - time_t t = localTime; char buf[9]; - if (t < 100000UL) { + if (localTime < 100000UL) { strncpy(buf, "--.--.--", sizeof(buf)); } else { snprintf(buf, sizeof(buf), "%02d.%02d.%02d", - day(t), month(t), year(t) % 100); + day(localTime), month(localTime), year(localTime) % 100); } int w = dpxTextPixelWidth(buf); int x = (DPX_MATRIX_W - w) / 2; diff --git a/usermods/dpx_matrix/dpx_matrix.h b/usermods/dpx_matrix/dpx_matrix.h index d1c13ddba6..03ea230922 100644 --- a/usermods/dpx_matrix/dpx_matrix.h +++ b/usermods/dpx_matrix/dpx_matrix.h @@ -152,10 +152,6 @@ class DpxMatrix : public Usermod { dpxCurrentApp < dpxApps.size() ? dpxApps[dpxCurrentApp].name.c_str() : "?", (unsigned)dpxCurrentApp, (unsigned)dpxApps.size()); Serial.printf("[dpx] Notifs : %u queued\n", (unsigned)dpxNotifQueue.size()); - Serial.printf("[dpx] NTP : enabled=%s synced=%s server=%s\n", - ntpEnabled ? "YES" : "NO", - (localTime > 100000UL) ? "YES" : "NO", - ntpServerName); Serial.printf("[dpx] Time : %02d:%02d:%02d (localTime=%lu)\n", hour(localTime), minute(localTime), second(localTime), (unsigned long)localTime); Serial.printf("[dpx] Uptime : %lus\n", millis() / 1000); From d8b6ca8645c0c167a96fe5ef363ba74d5c3103af Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 18 Jul 2026 14:54:34 -0400 Subject: [PATCH 8/9] refactor: replace handleOverlayDraw with proper WLED effect registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Register 'dpx Matrix' as WLED effect #200 via strip.addEffect() - dpxSetPixel/dpxGetPixel/dpxClear now use SEGMENT APIs (setPixelColorXY) → brightness, transitions, power-fade, and 2D panel mapping all work natively - handleOverlayDraw() removed entirely - dpxActivateEffect(): auto-switch to dpx Matrix when TC/notify/app arrives - 'WLED' rotation slot now switches AWAY to DNA Spiral (passthrough restored) - _dpxEffectId moved to dpx_apps.h so it's visible before first use - firstboot default fx updated to 200 (dpx Matrix) --- usermods/dpx_matrix/dpx_apps.h | 25 +++++++- usermods/dpx_matrix/dpx_firstboot.h | 2 +- usermods/dpx_matrix/dpx_matrix.h | 79 ++++++++++--------------- usermods/dpx_matrix/dpx_notifications.h | 1 + usermods/dpx_matrix/dpx_tc.h | 1 + usermods/dpx_matrix/dpx_text.h | 18 +++--- 6 files changed, 67 insertions(+), 59 deletions(-) diff --git a/usermods/dpx_matrix/dpx_apps.h b/usermods/dpx_matrix/dpx_apps.h index 96b55f3196..af82242c25 100644 --- a/usermods/dpx_matrix/dpx_apps.h +++ b/usermods/dpx_matrix/dpx_apps.h @@ -85,6 +85,17 @@ struct DpxOscListener { }; // ── Global app state ────────────────────────────────────────────────────────── +// Effect ID assigned by strip.addEffect() in DpxMatrix::setup(). +static uint8_t _dpxEffectId = 255; + +// Switch the main segment to dpx Matrix effect if not already active. +static inline void dpxActivateEffect() { + if (_dpxEffectId != 255 && strip.getMainSegment().mode != _dpxEffectId) { + strip.getMainSegment().setMode(_dpxEffectId); + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } +} + static std::vector dpxApps; // ordered app loop static std::map dpxCustom; // named custom apps static std::set dpxHiddenApps; // removed from rotation (incl. natives) @@ -283,7 +294,8 @@ static void dpxSetCustomApp(const String& name, const char* json) { DpxCustomApp app = dpxParseApp(json); if (app.valid) { dpxCustom[name] = app; - dpxHiddenApps.erase(name); // restore if previously removed + dpxHiddenApps.erase(name); + dpxActivateEffect(); // incoming app — switch display to dpx Matrix if (app.save) { LittleFS.mkdir("/CUSTOMAPPS"); File f = LittleFS.open("/CUSTOMAPPS/" + name + ".json", "w"); @@ -326,6 +338,7 @@ static bool dpxSwitchToApp(const char* json) { dpxCurrentApp = i; dpxAppStartMs = millis(); dpxScroll.stop(); + dpxActivateEffect(); // switch display to dpx Matrix return true; } } @@ -417,7 +430,15 @@ static void dpxRenderCurrentApp() { DpxApp& app = dpxApps[dpxCurrentApp]; if (app.isNative) { - if (app.name == "WLED") return; // passthrough — WLED effect renders unobstructed + if (app.name == "WLED") { + // Passthrough: switch away from dpx Matrix so WLED effects show. + // Switches to DNA Spiral (182); user can change via WLED UI. + if (_dpxEffectId != 255 && strip.getMainSegment().mode == _dpxEffectId) { + strip.getMainSegment().setMode(FX_MODE_2DDNASPIRAL); + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + return; + } dpxClear(); if (app.name == "Time") dpxRenderNativeTime(); else if (app.name == "Date") dpxRenderNativeDate(); diff --git a/usermods/dpx_matrix/dpx_firstboot.h b/usermods/dpx_matrix/dpx_firstboot.h index cd90213f29..d0e477c13a 100644 --- a/usermods/dpx_matrix/dpx_firstboot.h +++ b/usermods/dpx_matrix/dpx_firstboot.h @@ -95,7 +95,7 @@ static void dpxFirstBoot() { doc["def"]["ps"] = 0; doc["def"]["on"] = true; doc["def"]["bri"] = 128; - doc["def"]["fx"] = 182; // 2D DNA Spiral — works great on 32×8 matrix + doc["def"]["fx"] = 200; // dpx Matrix effect (registered by dpx_matrix usermod) doc["ota"]["lock"] = false; diff --git a/usermods/dpx_matrix/dpx_matrix.h b/usermods/dpx_matrix/dpx_matrix.h index 03ea230922..9b87ffd852 100644 --- a/usermods/dpx_matrix/dpx_matrix.h +++ b/usermods/dpx_matrix/dpx_matrix.h @@ -38,22 +38,32 @@ #include "dpx_mqtt.h" #include "dpx_api.h" +// ── dpx Matrix WLED effect ──────────────────────────────────────────────────── +// Registered as a proper WLED effect so brightness, transitions, and power-fade +// all work natively. Replaces the old handleOverlayDraw() hack. +// _dpxEffectId is declared in dpx_apps.h and assigned in DpxMatrix::setup(). + +static void mode_dpx_matrix() { + // Notifications take priority + if (dpxNotifTick()) { + dpxRenderNotification(); + } else { + dpxRenderCurrentApp(); + } + // Text overlay + pixel effects on top + dpxRenderOverlays(); + // Corner indicator dots (topmost layer) + if (dpxIndicator[0]) SEGMENT.setPixelColorXY(0, 0, dpxIndicator[0]); + if (dpxIndicator[1]) SEGMENT.setPixelColorXY(31, 0, dpxIndicator[1]); + if (dpxIndicator[2]) SEGMENT.setPixelColorXY(0, 7, dpxIndicator[2]); +} + class DpxMatrix : public Usermod { private: bool _initDone = false; bool dpxEnabled = true; - // Render the 3 indicator pixels (corner dots). - // Indicator 1 = top-left (pixel 0) - // Indicator 2 = top-right (pixel 31) - // Indicator 3 = bottom-left (pixel 224) - void renderIndicators() { - if (dpxIndicator[0]) strip.setPixelColor(0, dpxIndicator[0]); - if (dpxIndicator[1]) strip.setPixelColor(31, dpxIndicator[1]); - if (dpxIndicator[2]) strip.setPixelColor(224, dpxIndicator[2]); - } - public: static const char _name[]; @@ -76,11 +86,19 @@ class DpxMatrix : public Usermod { // NOTE: dpxOscBegin() is called in connected() once WiFi is up. // Opening a UDP socket before lwip is ready crashes the device. + // Register dpx Matrix as a WLED effect — this replaces handleOverlayDraw. + // Using SEGMENT APIs means brightness/transitions/power-fade work natively. + _dpxEffectId = strip.addEffect(200, &mode_dpx_matrix, + "dpx Matrix;!;2"); // 2D capable + // Switch the main segment to our effect on startup + strip.getMainSegment().setMode(_dpxEffectId); + stateUpdated(CALL_MODE_INIT); + // Register HTTP routes dpxRegisterRoutes(); _initDone = true; - DEBUG_PRINTLN(F("DpxMatrix: setup complete")); + DEBUG_PRINTF("DpxMatrix: setup complete, effect id=%d\n", _dpxEffectId); } void connected() override { @@ -252,42 +270,9 @@ class DpxMatrix : public Usermod { return true; // always consume — prevent WLED double-acting on these pins } - void handleOverlayDraw() override { - if (!_initDone || !dpxEnabled) return; - - // Notifications take priority over the app loop - if (dpxNotifTick()) { - dpxRenderNotification(); - } else { - dpxRenderCurrentApp(); - } - - // Pixel effects + text overlay on top of app content - // Per-app overlay: activate the pixel effect requested by the current - // app or notification. Resets when the displayed item changes. - { - String wantEffect; - if (dpxNotifActive && dpxCurrentNotif.data.valid) - wantEffect = dpxCurrentNotif.data.overlay; - else if (!dpxApps.empty() && !dpxApps[dpxCurrentApp].isNative) - wantEffect = dpxApps[dpxCurrentApp].data.overlay; - - static String _prevAppEffect; - if (wantEffect != _prevAppEffect) { - _prevAppEffect = wantEffect; - if (wantEffect.length() && wantEffect != "none") { - String j = String("{\"name\":\"") + wantEffect + "\",\"intensity\":60}"; - dpxSetPixelEffect(j.c_str()); - } else { - dpxClearPixelEffect(); - } - } - } - dpxRenderOverlays(); - - // Indicator corner dots (topmost layer) - renderIndicators(); - } + // handleOverlayDraw() removed — rendering now happens in mode_dpx_matrix() + // which is a proper WLED effect registered in setup(). This gives correct + // brightness scaling, transitions, and power-fade for free. // ── MQTT integration ────────────────────────────────────────────────── void onMqttConnect(bool /*sessionPresent*/) override { diff --git a/usermods/dpx_matrix/dpx_notifications.h b/usermods/dpx_matrix/dpx_notifications.h index 63d1b5b62f..72dd2ecdb4 100644 --- a/usermods/dpx_matrix/dpx_notifications.h +++ b/usermods/dpx_matrix/dpx_notifications.h @@ -47,6 +47,7 @@ static bool dpxPushNotification(const char* json) { dpxNotifActive = false; } dpxNotifQueue.push_back(notif); + dpxActivateEffect(); // ensure dpx Matrix effect is showing return true; } diff --git a/usermods/dpx_matrix/dpx_tc.h b/usermods/dpx_matrix/dpx_tc.h index 272452ee50..0c1fc89e90 100644 --- a/usermods/dpx_matrix/dpx_tc.h +++ b/usermods/dpx_matrix/dpx_tc.h @@ -93,6 +93,7 @@ static void dpxPushTC(const String& tc, int fps = 30) { } dpxAutoTrans = false; dpxTcLocked = true; + dpxActivateEffect(); // ensure dpx Matrix effect is showing } } diff --git a/usermods/dpx_matrix/dpx_text.h b/usermods/dpx_matrix/dpx_text.h index 9ea1bd471c..522879a067 100644 --- a/usermods/dpx_matrix/dpx_text.h +++ b/usermods/dpx_matrix/dpx_text.h @@ -21,28 +21,28 @@ static const int DPX_MATRIX_W = 32; static const int DPX_MATRIX_H = 8; -// ── Raw pixel write ──────────────────────────────────────────────────────────── +// ── Pixel write via SEGMENT ──────────────────────────────────────────────────── +// Using SEGMENT.setPixelColorXY() instead of strip.setPixelColor() means WLED +// handles brightness, transitions, power-fade, and 2D panel mapping (incl. +// serpentine) automatically. Only valid from within an effect function context. static inline void dpxSetPixel(int x, int y, uint32_t color) { if (x < 0 || x >= DPX_MATRIX_W || y < 0 || y >= DPX_MATRIX_H) return; - strip.setPixelColor(y * DPX_MATRIX_W + x, color); + SEGMENT.setPixelColorXY(x, y, color); } static inline uint32_t dpxGetPixel(int x, int y) { if (x < 0 || x >= DPX_MATRIX_W || y < 0 || y >= DPX_MATRIX_H) return 0; - return strip.getPixelColor(y * DPX_MATRIX_W + x); + return SEGMENT.getPixelColorXY(x, y); } -// ── Clear a rectangular region ──────────────────────────────────────────────── +// ── Fill / clear ─────────────────────────────────────────────────────────────── static inline void dpxFillRect(int x, int y, int w, int h, uint32_t color) { for (int row = y; row < y + h; row++) for (int col = x; col < x + w; col++) - dpxSetPixel(col, row, color); + SEGMENT.setPixelColorXY(col, row, color); } -// Clear entire matrix to black. -static inline void dpxClear() { - dpxFillRect(0, 0, DPX_MATRIX_W, DPX_MATRIX_H, 0x000000); -} +static inline void dpxClear() { SEGMENT.fill(0); } // ── Rainbow colour for a character index ────────────────────────────────────── static inline uint32_t dpxRainbowColor(int charIdx, int totalChars) { From 2814435d7893f314af468a1409d520b59af3617a Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 18 Jul 2026 15:07:44 -0400 Subject: [PATCH 9/9] fix: remove WLED slot from rotation; fix effect ID auto-assign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - WLED slot removed from native app list — dpx Matrix IS the effect, there is nothing underneath to passthrough to - Effect registered with ID 255 (auto-assign) instead of 200, which conflicted with existing built-in effects - Dead WLED passthrough handler removed from dpxRenderCurrentApp - firstboot: def.fx removed (effect ID is dynamic, set via dpxActivateEffect) --- usermods/dpx_matrix/dpx_apps.h | 15 +++------------ usermods/dpx_matrix/dpx_firstboot.h | 3 ++- usermods/dpx_matrix/dpx_matrix.h | 4 ++-- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/usermods/dpx_matrix/dpx_apps.h b/usermods/dpx_matrix/dpx_apps.h index af82242c25..b06dbe4b52 100644 --- a/usermods/dpx_matrix/dpx_apps.h +++ b/usermods/dpx_matrix/dpx_apps.h @@ -73,7 +73,7 @@ struct DpxCustomApp { struct DpxApp { String name; DpxCustomApp data; - bool isNative = false; // Time, Date, WLED etc. + bool isNative = false; // Time, Date — built-in apps bool muted = false; // if true, skipped in rotation }; @@ -261,7 +261,7 @@ static bool dpxRenderApp(DpxCustomApp& app) { static void dpxRebuildLoop() { std::vector newList; // Native apps — included unless user deleted them from the rotation - const char* natives[] = {"Time", "Date", "WLED"}; + const char* natives[] = {"Time", "Date"}; // WLED removed — dpx Matrix IS the WLED effect for (auto n : natives) { if (dpxHiddenApps.find(String(n)) == dpxHiddenApps.end()) { DpxApp a; a.name = n; a.isNative = true; @@ -283,7 +283,7 @@ static void dpxRebuildLoop() { } // Add or update a custom app. Empty body = remove from rotation. -// Native apps (Time, Date, WLED) are hidden (not deleted); custom apps are erased. +// Native apps (Time, Date) are hidden (not deleted); custom apps are erased. static void dpxSetCustomApp(const String& name, const char* json) { if (!json || strlen(json) <= 2) { // Remove from rotation — custom erased, natives hidden @@ -430,15 +430,6 @@ static void dpxRenderCurrentApp() { DpxApp& app = dpxApps[dpxCurrentApp]; if (app.isNative) { - if (app.name == "WLED") { - // Passthrough: switch away from dpx Matrix so WLED effects show. - // Switches to DNA Spiral (182); user can change via WLED UI. - if (_dpxEffectId != 255 && strip.getMainSegment().mode == _dpxEffectId) { - strip.getMainSegment().setMode(FX_MODE_2DDNASPIRAL); - stateUpdated(CALL_MODE_DIRECT_CHANGE); - } - return; - } dpxClear(); if (app.name == "Time") dpxRenderNativeTime(); else if (app.name == "Date") dpxRenderNativeDate(); diff --git a/usermods/dpx_matrix/dpx_firstboot.h b/usermods/dpx_matrix/dpx_firstboot.h index d0e477c13a..6de1af7e09 100644 --- a/usermods/dpx_matrix/dpx_firstboot.h +++ b/usermods/dpx_matrix/dpx_firstboot.h @@ -95,7 +95,8 @@ static void dpxFirstBoot() { doc["def"]["ps"] = 0; doc["def"]["on"] = true; doc["def"]["bri"] = 128; - doc["def"]["fx"] = 200; // dpx Matrix effect (registered by dpx_matrix usermod) + // def.fx intentionally omitted — dpxActivateEffect() in connected() sets + // the correct dynamic effect ID after strip.addEffect() has run. doc["ota"]["lock"] = false; diff --git a/usermods/dpx_matrix/dpx_matrix.h b/usermods/dpx_matrix/dpx_matrix.h index 9b87ffd852..a0d0b78566 100644 --- a/usermods/dpx_matrix/dpx_matrix.h +++ b/usermods/dpx_matrix/dpx_matrix.h @@ -88,8 +88,8 @@ class DpxMatrix : public Usermod { // Register dpx Matrix as a WLED effect — this replaces handleOverlayDraw. // Using SEGMENT APIs means brightness/transitions/power-fade work natively. - _dpxEffectId = strip.addEffect(200, &mode_dpx_matrix, - "dpx Matrix;!;2"); // 2D capable + _dpxEffectId = strip.addEffect(255, &mode_dpx_matrix, + "dpx Matrix;!;2"); // 255 = auto-assign next available ID // Switch the main segment to our effect on startup strip.getMainSegment().setMode(_dpxEffectId); stateUpdated(CALL_MODE_INIT);