https://github.com/luc-github/esp3d-webinstaller
Web Installer for ESP32 projects
https://github.com/luc-github/esp3d-webinstaller
Last synced: 18 days ago
JSON representation
Web Installer for ESP32 projects
- Host: GitHub
- URL: https://github.com/luc-github/esp3d-webinstaller
- Owner: luc-github
- License: gpl-3.0
- Created: 2025-12-14T01:52:22.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-01-23T05:14:28.000Z (about 1 month ago)
- Last Synced: 2026-01-23T22:44:14.872Z (about 1 month ago)
- Language: JavaScript
- Size: 3.87 MB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ESP3D Web Installer 
[](https://www.gnu.org/licenses/lgpl-3.0)
A modern, browser-based firmware installer for ESP32 devices using the Web Serial API. Flash your ESP32 directly from your browser without installing any software.

> [!WARNING]
>### Disclaimer
> The software is provided 'as is,' without any warranty of any kind, expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software.
>It is essential that you carefully read and understand this disclaimer before using this software and its components. If you do not agree with any part of this disclaimer, please refrain from using the software.
## β¨ Features
- **No installation required** - Works directly in Chrome, Edge, or Opera
- **Multi-project support** - Configure multiple firmware projects with a 3D carousel selector
- **Multi-language support** - English and French included, easily extensible
- **Progress tracking** - Real-time progress bar and detailed console logs
- **Error categorization** - Detailed error logging with configurable filtering
- **Flash statistics** - Track successful flashes per project
- **Release notes link** - Clickable version with π icon linking to release notes
- **Fully customizable** - Branding, colors, footer links via configuration files
- **Privacy-focused** - All firmware flashing happens locally in your browser
- **Offline capable** - No external CDN dependencies (ESPTool.js hosted locally)
## π Quick Start
### Prerequisites
- A web server with PHP support (Apache, Nginx, or local development server)
- A compatible browser: Chrome 89+, Edge 89+, or Opera 75+
- ESP32 device with USB connection
### Installation
1. **Clone the repository:**
```bash
git clone https://github.com/luc-github/esp3d-webinstaller.git
cd esp3d-webinstaller
```
2. **Download ESPTool.js bundle:**
```bash
curl -L "https://unpkg.com/esptool-js@0.4.5/bundle.js" -o js/esptool-bundle.js
```
Or download manually from [unpkg.com/esptool-js@0.4.5/bundle.js](https://unpkg.com/esptool-js@0.4.5/bundle.js)
3. **Add your firmware files:**
```
firmware/
βββ your-project/
βββ bootloader.bin
βββ partitions.bin
βββ firmware.bin
```
4. **Configure your project** (see [Configuration](#-configuration) section)
5. **Deploy to your web server** or test locally:
```bash
# Using PHP built-in server
php -S localhost:8000
```
6. **Open in browser:** `http://localhost:8000`
## π Project Structure
```
esp3d-webinstaller/
βββ index.html # Main application page
βββ privacy.html # Privacy policy page
βββ terms.html # Terms of service page
βββ style.css # Application styles
β
βββ js/
β βββ script.js # Main application logic
β βββ esptool-bundle.js # ESPTool.js library (download separately)
β
βββ config.json # Project/firmware configuration
βββ page-config.json # Page branding and settings
β
βββ lang/
β βββ en.json # English translations
β βββ fr.json # French translations
β
βββ log-flash.php # Flash event logging endpoint
βββ get-flash-counts.php # Retrieve flash statistics
βββ get-flash-errors.php # Retrieve detailed error logs
βββ flash-counts.json # Flash statistics data
βββ flash-errors.json # Detailed error logs
β
βββ images/
β βββ powered-logo.png # Header logo
β βββ favicon.ico # Browser favicon
β βββ espressif.png # Credits logo
β
βββ firmware/
βββ your-project/
βββ bootloader.bin
βββ partitions.bin
βββ firmware.bin
```
## βοΈ Configuration
### `config.json` - Firmware Projects
This file defines the firmware projects available in the installer.
```json
{
"projects": [
{
"id": "my-project",
"name": "My ESP32 Project",
"enabled": true,
"description": {
"en": "English description of your project",
"fr": "Description franΓ§aise de votre projet"
},
"version": "1.0.0",
"releaseNotes": "https://github.com/your-repo/releases/tag/v1.0.0",
"firmware": [
{ "path": "my-project/bootloader.bin", "offset": "0x1000" },
{ "path": "my-project/partitions.bin", "offset": "0x8000" },
{ "path": "my-project/firmware.bin", "offset": "0x10000" }
],
"image": "images/my-project.png",
"icon": "images/my-project-icon.svg",
"url": "https://your-project-website.com",
"documentation": "https://your-project-docs.com",
"badge": {
"en": "Stable",
"fr": "Stable"
}
}
]
}
```
| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique identifier for the project |
| `name` | string | Display name shown in the carousel |
| `enabled` | boolean | Set to `false` to show as "coming soon" |
| `description` | object | Localized descriptions (en, fr, etc.) |
| `version` | string | Firmware version displayed on the card |
| `releaseNotes` | string | URL to release notes (optional). If set, version becomes clickable with π icon |
| `firmware` | array/string | Firmware files with flash offsets |
| `image` | string | Project card image (optional) |
| `icon` | string | Small icon for the card header (optional) |
| `url` | string | Link to project website (optional) |
| `documentation` | string | Link to documentation (optional) |
| `badge` | object | Localized badge text (e.g., "Beta", "Stable") |
### `page-config.json` - Page Settings
This file configures branding, links, and visual settings.
```json
{
"branding": {
"logo": "images/powered-logo.png",
"favicon": "images/favicon.ico"
},
},
"languages": [
{
"code": "en",
"name": "English",
"default": true
},
{
"code": "fr",
"name": "FranΓ§ais"
}
],
"links": {
"links": {
"github": {
"enabled": true,
"url": "https://github.com/your-repo/issues/new"
}
},
"footer": {
"enabled": true,
"links": [
{ "key": "privacyPolicy", "url": "privacy.html" },
{ "key": "termsOfService", "url": "terms.html" }
]
},
"browser_compatibility": {
"show_warning": true,
"supported_browsers": ["Chrome", "Edge", "Opera"]
},
"theme": {
"primary_color": "#667eea",
"secondary_color": "#764ba2",
"success_color": "#00ff00",
"error_color": "#ff5555",
"warning_color": "#ffaa00"
},
},
},
},
"audio_feedback": {
"enabled": true,
"verbosity": "normal",
"volume": 0.7,
"events": {
"start": "sounds/[lang]/start.mp3",
"boot_prompt": "sounds/[lang]/press-boot.mp3",
"connected": "sounds/[lang]/connected.mp3",
"erasing": "sounds/[lang]/erasing.mp3",
"flashing_start": "sounds/[lang]/flashing-start.mp3",
"success": "sounds/[lang]/success.mp3",
"error": "sounds/error.mp3"
}
}
}
```
| `analytics`|`false` for static hosting (GitHub Pages),`true` for PHP server with logging |
| `branding` | Logo and favicon paths |
| `languages` | Available languages configuration |
| `links.github` | "Report Issue" button configuration |
| `footer` | Footer visibility and legal page links |
| `browser_compatibility` | Warning for unsupported browsers |
| `theme` | Color scheme (CSS variables) |
| `error_logging` | Configure which error categories are logged (optional) |
| `audio_feedback` | Audio notification system (optional) |
#### Error Logging Configuration
The `error_logging` section allows you to filter which error categories are sent to the server. This is useful to ignore common user actions like cancelling the port selection dialog.
```json
"error_logging": {
"enabled": true,
"categories": {
"user_cancel": false,
"port_busy": true,
"connection_timeout": true,
"download_failed": true,
"hardware_error": true,
"wrong_browser": false,
"flash_error": true,
"unknown": true
}
}
```
| Category | Default | Description |
|----------|---------|-------------|
| `user_cancel` | `false` | User cancelled port selection or operation |
| `port_busy` | `true` | Serial port in use by another application |
| `connection_timeout` | `true` | Timeout connecting to ESP32 (BOOT button not pressed) |
| `download_failed` | `true` | Failed to download firmware files |
| `hardware_error` | `true` | Chip or flash memory error |
| `wrong_browser` | `false` | Browser doesn't support Web Serial API |
| `flash_error` | `true` | Generic flash error |
| `unknown` | `true` | Uncategorized errors |
Set a category to `false` to stop logging that error type. If `error_logging` section is omitted, all errors are logged by default.
#### Languages Configuration
The `languages` section configures which languages are available. The language selector automatically hides when only one language is configured.
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `code` | string | Yes | Language code (must match filename in `lang/` folder) |
| `name` | string | Yes | Display name in language selector |
| `default` | boolean | No | Set to `true` for default language (only one) |
**Examples:**
```json
// Multiple languages (selector visible)
"languages": [
{ "code": "en", "name": "English", "default": true },
{ "code": "fr", "name": "FranΓ§ais" },
{ "code": "es", "name": "EspaΓ±ol" }
]
// Single language (selector hidden)
"languages": [
{ "code": "en", "name": "English", "default": true }
]
// If omitted, defaults to English only
```
**Adding a new language:**
1. Create translation file: `lang/es.json` (copy from `lang/en.json`)
2. Translate all values in the file
3. Add to `page-config.json`:
```json
{ "code": "es", "name": "EspaΓ±ol" }
```
No code changes needed - the language selector updates automatically!
#### Audio Notification System
The audio notification system provides real-time audio feedback throughout the entire flashing process. All sounds are **completely optional** and **fully configurable** with three verbosity levels.
**Verbosity Levels:**
- **Minimal** π - Essential sounds only (start, success, error)
- **Normal** π - Key milestones (recommended for most users)
- **Verbose** π’ - Every step with detailed feedback
##### Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enabled` | boolean | `false` | Enable/disable audio feedback |
| `verbosity` | string | `"normal"` | Audio level: `"minimal"`, `"normal"`, or `"verbose"` |
| `volume` | number | `0.7` | Global volume (0.0 to 1.0) |
| `events` | object | `{}` | Map of events to sound files |
##### Audio Events by Verbosity Level
**Minimal (3 events):**
- `start` - Flash process begins
- `success` - Flash completed successfully
- `error` - Flash failed (categorized by error type)
**Normal (7 events):**
All minimal events plus:
- `boot_prompt` - "Press and hold BOOT button"
- `connected` - Connected to ESP32
- `erasing` - Erasing flash memory
- `flashing_start` - Writing firmware begins
**Verbose (14 events):**
All normal events plus:
- `dialog_open` - Port selection dialog opens
- `port_selected` - User selected a port
- `connecting` - Attempting connection
- `erase_complete` - Erase finished
- `flashing_progress` - Progress milestones (25%, 50%, 75%)
- `writing_complete` - All data written
- `rebooting` - Device rebooting
##### Error Categories
Error sounds are automatically categorized:
| Category | Triggered when | Example sound |
|----------|----------------|---------------|
| `user_cancel` | User cancelled port selection | Soft/gentle tone |
| `connection_timeout` | Timeout connecting to ESP32 | Clock/timeout beep |
| `port_busy` | Port in use by another app | Busy signal |
| `hardware_error` | ESP32 chip/flash error | Critical error beep |
| `download_failed` | Firmware download failed | Download error |
| `wrong_browser` | Unsupported browser | Browser error |
| `flash_error` | Generic flash error | Standard error beep |
##### Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enabled` | boolean | `false` | Enable/disable audio feedback |
| `verbosity` | string | `"normal"` | Audio level: `"minimal"`, `"normal"`, or `"verbose"` |
| `volume` | number | `0.7` | Global volume (0.0 to 1.0) |
| `events` | object | `{}` | Map of events to sound files |
##### Multilingual Audio Support
Audio files can be organized by language using the `[lang]` placeholder in paths. The system automatically replaces `[lang]` with the current language code.
**Example configuration:**
```json
"audio_feedback": {
"enabled": true,
"events": {
"start": "sounds/[lang]/start.mp3",
"boot_prompt": "sounds/[lang]/press-boot.mp3",
"connected": "sounds/[lang]/connected.mp3",
"success": "sounds/[lang]/success.mp3",
"error": "sounds/error.mp3"
}
}
```
**File structure:**
```
sounds/
βββ en/
β βββ start.mp3 "Ok let's go!"
β βββ press-boot.mp3 "Press and hold BOOT button"
β βββ connected.mp3 "Connected"
β βββ success.mp3 "Success!"
βββ fr/
β βββ start.mp3 "C'est parti !"
β βββ press-boot.mp3 "Appuyez sur BOOT"
β βββ connected.mp3 "ConnectΓ©"
β βββ success.mp3 "SuccΓ¨s !"
βββ error.mp3 β Universal sound (no translation)
```
**How it works:**
- User selects English β `sounds/[lang]/start.mp3` becomes `sounds/en/start.mp3`
- User selects French β `sounds/[lang]/start.mp3` becomes `sounds/fr/start.mp3`
**Mix and match:**
You can combine multilingual and universal sounds. Use `[lang]` for verbal messages that need translation, and direct paths for universal sound effects (beeps, tones).
##### Audio Events by Verbosity Level
##### Audio Events by Verbosity Level
**Minimal (3 events):**
- `start` - Flash process begins
- `success` - Flash completed successfully
- `error` - Flash failed (categorized by error type)
**Normal (7 events):**
All minimal events plus:
- `boot_prompt` - "Press and hold BOOT button"
- `connected` - Connected to ESP32
- `erasing` - Erasing flash memory
- `flashing_start` - Writing firmware begins
**Verbose (14 events):**
All normal events plus:
- `dialog_open` - Port selection dialog opens
- `port_selected` - User selected a port
- `connecting` - Attempting connection
- `erase_complete` - Erase finished
- `flashing_progress` - Progress milestones (25%, 50%, 75%)
- `writing_complete` - All data written
- `rebooting` - Device rebooting
##### Error Categories
Error sounds are automatically categorized:
| Category | Triggered when | Example sound |
|----------|----------------|---------------|
| `user_cancel` | User cancelled port selection | Soft/gentle tone |
| `connection_timeout` | Timeout connecting to ESP32 | Clock/timeout beep |
| `port_busy` | Port in use by another app | Busy signal |
| `hardware_error` | ESP32 chip/flash error | Critical error beep |
| `download_failed` | Firmware download failed | Download error |
| `wrong_browser` | Unsupported browser | Browser error |
| `flash_error` | Generic flash error | Standard error beep |
##### Configuration Examples
**Minimal (essentials only):**
```json
{
"audio_feedback": {
"enabled": true,
"verbosity": "minimal",
"volume": 0.7,
"events": {
"start": "sounds/start.mp3",
"success": "sounds/success.mp3",
"error": "sounds/error.mp3"
}
}
}
```
**Normal (recommended):**
```json
{
"audio_feedback": {
"enabled": true,
"verbosity": "normal",
"volume": 0.7,
"events": {
"start": "sounds/start.mp3",
"boot_prompt": "sounds/press-boot.mp3",
"connected": "sounds/connected.mp3",
"erasing": "sounds/erasing.mp3",
"flashing_start": "sounds/flashing-start.mp3",
"success": "sounds/success.mp3",
"error": "sounds/error.mp3",
"error_user_cancel": "sounds/cancel.mp3",
"error_connection_timeout": "sounds/timeout.mp3",
"error_port_busy": "sounds/busy.mp3",
"error_hardware_error": "sounds/hardware-error.mp3"
}
}
}
```
**Verbose (full experience):**
```json
{
"audio_feedback": {
"enabled": true,
"verbosity": "verbose",
"volume": 0.7,
"events": {
"start": "sounds/start.mp3",
"dialog_open": "sounds/select-port.mp3",
"port_selected": "sounds/port-selected.mp3",
"boot_prompt": "sounds/press-boot.mp3",
"connecting": "sounds/connecting.mp3",
"connected": "sounds/connected.mp3",
"erasing": "sounds/erasing.mp3",
"erase_complete": "sounds/erase-complete.mp3",
"flashing_start": "sounds/flashing-start.mp3",
"flashing_progress": "sounds/progress.mp3",
"writing_complete": "sounds/writing-complete.mp3",
"rebooting": "sounds/rebooting.mp3",
"success": "sounds/success.mp3",
"error": "sounds/error.mp3",
"error_user_cancel": "sounds/cancel.mp3",
"error_connection_timeout": "sounds/timeout.mp3",
"error_port_busy": "sounds/busy.mp3",
"error_hardware_error": "sounds/hardware-error.mp3",
"error_download_failed": "sounds/download-error.mp3",
"error_wrong_browser": "sounds/browser-error.mp3",
"error_flash_error": "sounds/flash-error.mp3"
}
}
}
```
**File structure:**
```
esp3d-webinstaller/
βββ sounds/
β βββ start.mp3 # Flash begins
β βββ select-port.mp3 # Dialog opens (verbose)
β βββ port-selected.mp3 # Port selected (verbose)
β βββ press-boot.mp3 # BOOT button prompt
β βββ connecting.mp3 # Connecting (verbose)
β βββ connected.mp3 # Connected successfully
β βββ erasing.mp3 # Erasing flash
β βββ erase-complete.mp3 # Erase done (verbose)
β βββ flashing-start.mp3 # Writing begins
β βββ progress.mp3 # Progress milestone (verbose)
β βββ writing-complete.mp3 # Writing done (verbose)
β βββ rebooting.mp3 # Rebooting device (verbose)
β βββ success.mp3 # Success!
β βββ error.mp3 # Generic error
β βββ cancel.mp3 # User cancelled
β βββ timeout.mp3 # Connection timeout
β βββ busy.mp3 # Port busy
β βββ hardware-error.mp3 # Hardware error
β βββ download-error.mp3 # Download failed
β βββ browser-error.mp3 # Wrong browser
β βββ flash-error.mp3 # Flash error
βββ ...
```
**Getting sound files:**
- Text-to-speech: [ttsmaker.com](https://ttsmaker.com/)
- Sound effects: [freesound.org](https://freesound.org/), [mixkit.co](https://mixkit.co/)
- Keep files under 500KB each
> [!NOTE]
>
> All current sounds were created using [Elevenlabs](https://elevenlabs.io/) text-to-speech technology and the "Akito" voice preset.
>
> Certain sounds can be too long to play instantly. Because they are queued, playback may be delayed and fall out of sync with real-time actions. In these cases, omit sounds for steps that are too close in timing to preserve a natural audio flow.
## π Logging and Analytics
The installer includes a logging system to track flash statistics and errors, helping you understand usage patterns and debug issues.
### `flash-counts.json` - Statistics
Automatically updated with each flash attempt:
```json
{
"My ESP32 Project": {
"total": 150,
"success": 142,
"failed": 8
}
}
```
### `flash-errors.json` - Detailed Error Logs
Captures detailed information about failures:
```json
{
"lastUpdated": "2024-12-14T10:30:00Z",
"totalErrors": 8,
"categoryCounts": {
"connection_timeout": 3,
"user_cancel": 2,
"port_busy": 2,
"wrong_browser": 1
},
"entries": [
{
"id": "err_abc123",
"timestamp": "2024-12-14T10:30:00Z",
"project": "My ESP32 Project",
"error": "Timeout waiting for sync",
"category": "connection_timeout",
"context": {
"browser": { "name": "Chrome", "version": "120", "os": "Windows" },
"stage": "connecting"
}
}
]
}
```
### Error Categories
| Category | Description | Typical Cause |
|----------|-------------|---------------|
| `user_cancel` | User cancelled the operation | User didn't select a port |
| `port_busy` | Serial port unavailable | Another app using the port |
| `connection_timeout` | Timeout connecting to ESP32 | BOOT button not pressed |
| `download_failed` | Failed to download firmware | Network or server issue |
| `hardware_error` | Chip or flash memory error | Hardware problem |
| `wrong_browser` | Unsupported browser | Firefox, Safari, etc. |
| `flash_error` | Generic flash error | Various causes |
### API Endpoints
**Get flash counts:**
```
GET /get-flash-counts.php
```
**Get error summary:**
```
GET /get-flash-errors.php?summary=true
```
**Get filtered errors:**
```
GET /get-flash-errors.php?category=connection_timeout&limit=50
GET /get-flash-errors.php?project=My%20Project&limit=100
```
## π File Permissions
Ensure the PHP files can write to the JSON data files:
```bash
chmod 644 flash-counts.json flash-errors.json
chmod 755 log-flash.php get-flash-counts.php get-flash-errors.php
```
On some servers, you may need to set ownership:
```bash
chown www-data:www-data flash-counts.json flash-errors.json
```
## π Browser Support
| Browser | Minimum Version | Status |
|---------|----------------|--------|
| Chrome | 89+ | β
Fully supported |
| Edge | 89+ | β
Fully supported |
| Opera | 75+ | β
Fully supported |
| Firefox | - | β No Web Serial API |
| Safari | - | β No Web Serial API |
## π Deployment
### GitHub Pages (Static)
1. Set `"analytics": false` in `page-config.json`
2. Remove PHP files (not needed):
```bash
rm log-flash.php get-flash-counts.php get-flash-errors.php
rm flash-counts.json flash-errors.json
```
3. Push to GitHub and enable GitHub Pages in repository settings.
4. Your installer will be available at `https://username.github.io/repository/`
### PHP Server (With Analytics)
1. Set `"analytics": true` in `page-config.json`
2. Create the secret files directory (see Security section below for placement options)
3. Generate a secret key:
```bash
openssl rand -base64 32 > /path/to/secret_files/mykey.txt
```
4. Update the path in `log-flash.php` to match your setup:
```php
'secret_key_file' => __DIR__ . '/../secret_files/mykey.txt',
```
5. Set permissions:
```bash
chmod 700 /path/to/secret_files/
chmod 600 /path/to/secret_files/mykey.txt
chmod 644 flash-counts.json flash-errors.json
chmod 755 log-flash.php get-flash-counts.php get-flash-errors.php
```
6. Configure allowed origins in `log-flash.php`:
```php
'allowed_origins' => [
'localhost',
'yourdomain.com',
'www.yourdomain.com',
],
```
7. Deploy to your PHP-enabled web server.
## π Security (PHP Server)
When running with `analytics: true`, the following security measures are implemented:
| Security Layer | Description |
|----------------|-------------|
| **Secret Key File** | Verifies script runs on legitimate server (file outside web access) |
| **Rate Limiting** | Max 10 requests/minute, 50 requests/hour per IP |
| **Input Validation** | Sanitizes all input, limits string lengths |
| **File Size Limits** | Counts: 1MB max, Errors: 5MB max |
| **Origin Check** | Validates Referer/Origin header |
| **Honeypot** | Detects bot submissions |
| **Payload Limit** | Max 10KB per request |
### Secret Files Placement
#### Option A: Outside web root (Recommended)
Place `secret_files/` at the same level as your web root, not inside it:
```
/var/www/
βββ webinstaller/ <- Web root (HTTP accessible)
β βββ index.html
β βββ log-flash.php
β βββ flash-counts.json
β βββ ...
βββ secret_files/ <- Outside web root (NOT HTTP accessible)
βββ mykey.txt
βββ rate_limits.json <- Auto-generated
```
In `log-flash.php`, use:
```php
'secret_key_file' => __DIR__ . '/../secret_files/mykey.txt',
'rate_limit_file' => __DIR__ . '/../secret_files/rate_limits.json',
```
**β
No additional web server configuration needed** - the directory is simply not served.
#### Option B: Inside web root with access denied
If you cannot place files outside the web root, put `secret_files/` inside and block access:
```
/var/www/webinstaller/ <- Web root
βββ index.html
βββ log-flash.php
βββ secret_files/ <- Inside web root, access blocked
βββ .htaccess <- Required for Apache
βββ mykey.txt
βββ rate_limits.json
```
In `log-flash.php`, use:
```php
'secret_key_file' => __DIR__ . '/secret_files/mykey.txt',
'rate_limit_file' => __DIR__ . '/secret_files/rate_limits.json',
```
**Apache** - Create `secret_files/.htaccess`:
```apache
Require all denied
```
**Nginx** - Add to your server block:
```nginx
location /secret_files/ {
deny all;
return 403;
}
```
### Verify Security
Test that `secret_files/` is NOT accessible:
```bash
curl -I https://yourdomain.com/secret_files/mykey.txt
# Should return 403 Forbidden or 404 Not Found
```
## π οΈ Development
### Local Development Server
```bash
# PHP built-in server
php -S localhost:8000
# Or with Python
python -m http.server 8000
```
Note: PHP server is required for logging functionality.
### Updating ESPTool.js
To update to a newer version:
```bash
curl -L "https://unpkg.com/esptool-js@VERSION/bundle.js" -o js/esptool-bundle.js
```
Check [esptool-js releases](https://github.com/espressif/esptool-js/releases) for available versions.
## π€ Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
For questions and discussions, please use [GitHub Discussions](https://github.com/luc-github/esp3d-webinstaller/discussions).
## π License
This project is licensed under the **GNU Lesser General Public License v3.0** - see the [LICENSE](LICENSE) file for details.
## π Credits
### ESPTool.js
This project uses the excellent [esptool-js](https://github.com/espressif/esptool-js) library for ESP32 communication.
**esptool-js** is developed by [Espressif Systems](https://www.espressif.com/) and is licensed under the Apache License 2.0.
### Web Serial API
Communications with ESP32 are done using [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API).
The browser serial communication API from Mozilla.
Made with β€οΈ for the ESP32 community
