Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"permissions": {
"allow": [
"Bash(npm run build:*)",
"Bash(npm run pio:firmware:*)",
"Bash(npm run pio:monitor:*)",
"Bash(pio run:*)",
"Bash(tasklist:*)",
"Bash(findstr:*)",
"Bash(cmd //c \"tasklist | findstr python\")",
"Bash(npm run build:web:*)",
"Bash(npm run:*)",
"Bash(python:*)",
"WebFetch(domain:splitflap.local)",
"Bash(curl:*)",
"Bash(pio device list:*)"
],
"deny": [],
"ask": []
}
}
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,14 @@
.vscode
node_modules/
build/web/*
.idea
.idea

# Local configuration with credentials
platformio_override.ini
.env
secrets.h
credentials.json
src/credentials.h

# Claude Code local settings
.claude/settings.local.json
57 changes: 57 additions & 0 deletions ACCURACY_IMPROVEMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Split-Flap Display - Accuracy Improvements

## Proposed Enhancements for Long-Term Accuracy

### Priority 1: Missed Magnet Detection 🧲
**Problem**: No detection if a module completely misses the magnet during movement.
**Solution**: Track expected vs actual magnet crossings.
**Impact**: Critical safety check, prevents lost position tracking.

### Priority 2: Position Error Statistics 📊
**Problem**: Position errors are corrected but not logged or analyzed.
**Solution**: Track max error, average error, and correction frequency per module.
**Impact**: Diagnostics for maintenance, identify problematic modules.

### Priority 3: Adaptive Speed Control ⚡
**Problem**: Modules with mechanical issues run at same speed as good modules.
**Solution**: Reduce max speed for modules with high error rates.
**Impact**: Immediate accuracy improvement for problematic modules.

### Priority 4: Predictive Homing 🏠
**Problem**: Position drift can accumulate during long display sessions.
**Solution**: Periodically home during idle periods (e.g., every 5 minutes).
**Impact**: Prevents long-term drift, maintains calibration.

### Priority 5: Magnet Position Variance Tracking 📍
**Problem**: Fixed magnetPosition value doesn't adapt to mechanical wear.
**Solution**: Track actual detection positions and auto-adjust magnetPosition.
**Impact**: Self-calibrating system adapts to wear over time.

### Priority 6: Backlash Compensation 🔄
**Problem**: Stepper motors can have directional backlash.
**Solution**: Always approach target from same direction for small movements.
**Impact**: More consistent positioning.

### Priority 7: Temperature Compensation 🌡️
**Problem**: Thermal expansion may affect mechanical accuracy.
**Solution**: Track correlation between temperature and position errors.
**Impact**: Identify environmental factors affecting accuracy.

### Priority 8: Step Verification with Current Sensing ⚡
**Problem**: Missed steps not detected until next magnet pass.
**Solution**: Monitor motor current to detect binding/missed steps.
**Impact**: Real-time error detection (requires hardware modification).

---

## Implementation Notes

- Start with Priority 1-2 (diagnostics, non-invasive)
- Priority 3-5 provide active correction
- Priority 6-8 are advanced features for specific issues

## Code Locations

- `SplitFlapModule.h/cpp` - Module-level tracking
- `SplitFlapDisplay.cpp` - Movement and homing logic
- `SplitFlapWebServer.cpp` - Diagnostics endpoint (future)
175 changes: 175 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Split Flap Display firmware for ESP32-based modular split-flap displays with web interface control and MQTT support.

## Development Commands

### Build and Upload
```bash
# Full build (format, assets, firmware, filesystem)
npm run build

# Individual components
npm run pio:firmware # Upload firmware only
npm run pio:filesystem # Upload filesystem only
npm run pio # Upload both firmware and filesystem
```

### Code Formatting
```bash
npm run format # Format all code
npm run format:cpp # Format C++ files (requires clang-format)
npm run format:web # Format web assets with Prettier
```

### PlatformIO Commands
```bash
# Target specific board environment
pio run -t upload -e esp32_c3 # Default ESP32-C3
pio run -t upload -e esp32_s3 # ESP32-S3
pio run -t uploadfs -e <environment> # Upload filesystem only

# Monitor serial output
npm run pio:monitor
```

### OTA (Over-The-Air) Updates

**Setup Process:**
1. Set an OTA password in the web interface settings page (`Settings > General > OTA Password`)
2. The password is stored in the `otaPass` setting - if empty, OTA is disabled
3. When a password is set, the system requires a restart for OTA to become active

**How OTA Works:**
- `enableOta()` is called during startup if `otaPass` is configured
- Uses ArduinoOTA library with the mDNS hostname (default: `splitflap.local`)
- `handleOta()` is called in the main loop to process incoming OTA requests
- Supports both firmware (`U_FLASH`) and filesystem (`U_LITTLEFS`) updates
- During filesystem updates, LittleFS is unmounted/remounted automatically

**Uploading via OTA:**
```bash
# Use environment with _ota suffix
pio run -t upload -e esp32_c3_ota # For ESP32-C3
pio run -t upload -e esp32_s3_ota # For ESP32-S3
pio run -t uploadfs -e esp32_c3_ota # Upload filesystem only

# Configure authentication in platformio.ini
upload_flags = --auth=yourpassword # Must match web interface password
```

**PlatformIO OTA Configuration:**
- `upload_protocol=espota` - Uses ESP OTA protocol
- `upload_port=splitflap.local` - Default mDNS hostname (customizable in settings)
- Authentication required if password is set in device settings

**Important Notes:**
- OTA password changes require a device restart to take effect
- Progress is displayed via serial output during updates
- Network must be stable during upload to prevent corruption
- Device automatically reboots after successful OTA update

## Operation Modes

The display supports multiple operation modes controlled via web interface:
- **Mode 0**: Single input mode - displays a single text string
- **Mode 1**: Multi input mode - cycles through multiple text strings with delay
- **Mode 2**: Date mode - displays current date
- **Mode 3**: Time mode - displays current time
- **Mode 4**: Idle mode - no operation
- **Mode 5**: Random test mode - cycles through random characters
- **Mode 6**: Manual mode with special commands
- Accepts normal text input like mode 0
- Special command: `#home` - triggers homing sequence to reset all modules
- Command is cleared after execution

## Architecture

### Core Components

**Main Application** (`src/SplitFlapDisplay.ino`)
- Entry point initializing display, web server, and MQTT
- Configuration via JsonSettings with persistent storage

**SplitFlapDisplay** (`src/SplitFlapDisplay.h/.cpp`)
- Central controller managing up to 8 split-flap modules
- Handles string writing, positioning, and homing operations
- Interfaces with individual modules via I2C

**SplitFlapModule** (`src/SplitFlapModule.h/.cpp`)
- Controls individual split-flap units via PCF8575 I2C expander
- Manages stepper motor control and Hall effect sensor feedback
- Supports 37 or 48 character sets

**SplitFlapWebServer** (`src/SplitFlapWebServer.h/.cpp`)
- ESPAsyncWebServer-based web interface on port 80
- REST API endpoints for display control and configuration
- Serves minified web assets from LittleFS

**SplitFlapMqtt** (`src/SplitFlapMqtt.h/.cpp`)
- MQTT client for remote display control
- Publishes status updates and subscribes to command topics

**JsonSettings** (`src/JsonSettings.h/.cpp`)
- Persistent configuration storage in LittleFS
- Manages WiFi, MQTT, hardware, and operational settings

### Web Assets

Located in `src/web/`, built with Vite:
- `index.html/js` - Main control interface with Alpine.js
- `settings.html` - Configuration interface
- Tailwind CSS for styling
- Assets minified and copied to `.pio/build/littlefs/` during build

### Build Process

1. Vite builds and minifies web assets to `build/web/`
2. `build/scripts/gzip_littlefs.py` compresses assets to `.pio/build/littlefs/`
3. PlatformIO compiles firmware and uploads with LittleFS filesystem

## Hardware Configuration

- **I2C Communication**: Configurable SDA/SCL pins (default 8/9)
- **Module Addresses**: PCF8575 at 0x20-0x27 (configurable)
- **Stepper Control**: 2048 steps per rotation (default)
- **Position Feedback**: Hall effect sensor for homing
- **Character Sets**: 37 standard or 48 extended characters

### Module Offset Feature

The module offset system compensates for mechanical variations between split-flap modules:

**Two Types of Offsets:**
1. **moduleOffsets** (array): Individual offset for each module (default: `[0,0,0,0,0,0,0,0]`)
- Applied per-module to adjust for mechanical differences
- Configured in settings as comma-separated values
- Example: `[10, -5, 0, 15, 0, 0, -10, 20]` adjusts individual modules

2. **displayOffset** (single value): Global offset applied to all modules (default: `0`)
- Shifts the entire display's reference position
- Useful for adjusting all modules together

**How Offsets Work:**
- During initialization (`SplitFlapDisplay.cpp:36`), each module receives: `moduleOffsets[i] + displayOffset`
- This combined offset adjusts the `magnetPosition` in `SplitFlapModule` constructor
- The adjusted position becomes: `magnetPosition = magnetPos + stepOffset`
- Offsets are in motor steps (out of 2048 per rotation)
- Positive values rotate the reference position clockwise
- Negative values rotate counter-clockwise

**Practical Use:**
- If a module's flap doesn't align properly when homed, adjust its `moduleOffset`
- If the entire display is off by the same amount, adjust `displayOffset`
- Fine-tune via web interface settings page or MQTT configuration

**Dynamic Offset Updates:**
- Module offsets can now be updated dynamically without requiring a system restart
- When `moduleOffsets` or `displayOffset` settings are changed via the web interface, the system automatically calls `display.updateOffsets()`
- The `updateOffsets()` method reloads offset values from settings and applies them to each module immediately
- Each module stores both `baseMagnetPosition` (original) and `magnetPosition` (with offset applied) to enable dynamic updates
- The web server maintains a pointer to the display object to trigger updates when offset settings change
75 changes: 75 additions & 0 deletions CREDENTIALS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Credentials Management

This project uses a local credentials file to keep sensitive information out of version control.

## Setup for Local Development

1. **Copy the example credentials file:**
```bash
cp src/credentials.h.example src/credentials.h
```

2. **Edit `src/credentials.h` with your actual credentials:**
```cpp
#define WIFI_SSID "your_wifi_ssid"
#define WIFI_PASS "your_wifi_password"

#define MQTT_SERVER "your-mqtt-broker.com"
#define MQTT_PORT 1883
#define MQTT_USER "your_username"
#define MQTT_PASS "your_password"
```

3. **Build and upload:**
```bash
npm run build
```

The `credentials.h` file is in `.gitignore` and will never be committed to git.

## How It Works

- **`src/credentials.h.example`** - Template file (committed to git)
- **`src/credentials.h`** - Your local credentials (NOT in git, in .gitignore)
- **`src/SplitFlapDisplay.ino`** - Uses credentials if available, otherwise defaults to empty

The code uses `__has_include` to check if `credentials.h` exists:
- If it exists: Uses your local credentials as defaults
- If it doesn't exist: Uses empty defaults
- Either way: Settings can be configured via the web interface

## Alternative: Configure via Web Interface

You don't need to create `credentials.h` if you prefer to configure everything through the web interface:

1. Flash the firmware with default (empty) settings
2. Connect to the device's WiFi network
3. Open the settings page
4. Enter your WiFi and MQTT credentials
5. Save settings

Settings are persisted to the ESP32's flash storage.

## What's Gitignored

The following files are excluded from version control:
- `src/credentials.h` - Local MQTT and WiFi credentials
- `.env` - Environment variables
- `.claude/settings.local.json` - Claude Code local settings
- `secrets.h` - Alternative secrets file
- `credentials.json` - Alternative JSON credentials
- `platformio_override.ini` - PlatformIO overrides (if needed for other settings)

## What's Committed (Safe)

The following files ARE committed:
- `src/credentials.h.example` - Template with placeholder credentials
- `platformio.ini` - Main config WITHOUT credentials (references credentials.h)

## Security Best Practices

- Never commit credentials to git
- Use strong passwords for MQTT and OTA
- Change default passwords after initial setup
- Restrict MQTT broker access to authorized devices
- Use TLS/SSL for MQTT if possible (requires code modifications)
Loading