{"id":33346304,"url":"https://github.com/sfrechette/binary-clock-station","last_synced_at":"2026-04-13T13:02:55.066Z","repository":{"id":325315710,"uuid":"1090606563","full_name":"sfrechette/binary-clock-station","owner":"sfrechette","description":"A modern, optimized binary clock implementation for the LilyGo T-Display-S3 ESP32 board. Displays time in binary format using illuminated dots, with WiFi connectivity for automatic NTP time synchronization.","archived":false,"fork":false,"pushed_at":"2025-11-20T16:39:00.000Z","size":215,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-20T18:22:12.871Z","etag":null,"topics":["arduino","binary-clock","binaryclock","c","clock","cpp","esp32","esp32-s3","lilygo","lilygo-tdisplay-s3","platformio"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sfrechette.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-05T22:27:31.000Z","updated_at":"2025-11-20T16:39:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sfrechette/binary-clock-station","commit_stats":null,"previous_names":["sfrechette/binary-clock-station"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/sfrechette/binary-clock-station","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfrechette%2Fbinary-clock-station","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfrechette%2Fbinary-clock-station/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfrechette%2Fbinary-clock-station/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfrechette%2Fbinary-clock-station/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sfrechette","download_url":"https://codeload.github.com/sfrechette/binary-clock-station/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sfrechette%2Fbinary-clock-station/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285748794,"owners_count":27225088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-22T02:00:05.934Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","binary-clock","binaryclock","c","clock","cpp","esp32","esp32-s3","lilygo","lilygo-tdisplay-s3","platformio"],"created_at":"2025-11-22T07:00:37.630Z","updated_at":"2026-04-13T13:02:55.040Z","avatar_url":"https://github.com/sfrechette.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Binary Clock Station for LILYGO T-Display S3\n\nA modern, optimized binary clock implementation for the **LILYGO T-Display-S3** ESP32 board. Displays time in binary format using illuminated dots, with WiFi connectivity for automatic NTP time synchronization.\n\n![Hardware](https://img.shields.io/static/v1?label=Hardware\u0026message=LILYGO%20T-Display%20S3\u0026color=red)\n![ESP32-S3](https://img.shields.io/badge/ESP32-S3-blue)\n![Platform](https://img.shields.io/badge/Platform-PlatformIO-orange)\n![License](https://img.shields.io/badge/License-MIT-green)\n\n\u003cimg src=\"docs/images/binary-clock-station01.JPEG\" alt=\"LILYGO T-Display-S3 Display\" width=\"400\" /\u003e\n\u003cimg src=\"docs/images/binary-clock-station02.JPEG\" alt=\"LILYGO T-Display-S3 Display\" width=\"400\" /\u003e\n\n## Features\n\n### Core Functionality\n\n- **Binary Time Display**: Visual binary representation of current time (HH:MM:SS)\n- **Optimized LED Layout**: Each column displays only the necessary LEDs for its digit range\n  - Hours tens (0-2): 2 LEDs\n  - Hours ones (0-9): 4 LEDs\n  - Minutes tens (0-5): 3 LEDs\n  - Minutes ones (0-9): 4 LEDs\n  - Seconds tens (0-5): 3 LEDs\n  - Seconds ones (0-9): 4 LEDs\n- **NTP Time Sync**: Automatic time synchronization over WiFi\n- **Timezone Support**: Configurable timezone (default: EST/EDT)\n\n### User Interface\n\n- **Toggle Time Display** (GPIO 0 / BOOT button): Show/hide decimal time digits below binary display\n- **Brightness Control** (GPIO 14 / IO14 button): Cycle through 6 brightness levels (25, 75, 125, 175, 225, 255)\n- **Clean Visual Design**:\n  - White LEDs for \"on\" state\n  - Light grey LEDs for \"off\" state\n  - Centered display with proper spacing\n  - No screen flickering\n\n### Performance\n\n- **Memory Efficient**: Uses only 14% RAM and 11% Flash\n- **Fast Updates**: 100ms polling for responsive display\n- **Smart Rendering**: Only redraws when time changes\n- **Debounced Buttons**: 200ms debounce prevents accidental double-presses\n\n## Prerequisites\n\n### Hardware Requirements\n\n- **LILYGO T-Display-S3** ESP32-S3 development board\n  - 1.9\" LCD Display (320x170 ST7789)\n  - Built-in buttons (GPIO 0 and GPIO 14)\n  - WiFi connectivity\n\n### Software Requirements\n\n- **PlatformIO** (VS Code extension or CLI)\n- **Git** (for cloning the repository)\n- **USB-C cable** (for uploading firmware)\n\n### Network Requirements\n\n- WiFi network with internet access (for NTP time sync)\n- WiFi credentials (SSID and password)\n\n## Installation\n\n### 1. Clone the Repository\n\n```bash\ngit clone https://github.com/yourusername/binary-clock-station.git\ncd binary-clock-station\n```\n\n### 2. Configure WiFi Credentials\n\nCreate a `secrets.h` file in the `include/` directory:\n\n```bash\ncp include/secrets_template.h include/secrets.h\n```\n\nEdit `include/secrets.h` and add your WiFi credentials:\n\n```cpp\n#ifndef SECRETS_H\n#define SECRETS_H\n\n// WiFi credentials\n#define WIFI_SSID \"Your_WiFi_SSID\"\n#define WIFI_PASS \"Your_WiFi_Password\"\n\n#endif\n```\n\n\u003e **Note**: `secrets.h` is gitignored and will not be committed to version control.\n\n### 3. Configure Timezone (Optional)\n\nEdit `src/config.h` to set your timezone:\n\n```cpp\n#define TIMEZONE \"EST5EDT,M3.2.0/2,M11.1.0/2\"  // Change to your timezone\n```\n\nCommon timezone strings:\n\n- EST/EDT: `\"EST5EDT,M3.2.0/2,M11.1.0/2\"`\n- PST/PDT: `\"PST8PDT,M3.2.0/2,M11.1.0/2\"`\n- CST/CDT: `\"CST6CDT,M3.2.0/2,M11.1.0/2\"`\n- MST/MDT: `\"MST7MDT,M3.2.0/2,M11.1.0/2\"`\n- UTC: `\"UTC0\"`\n\n### 4. Build and Upload\n\n#### Using PlatformIO CLI\n\n```bash\n# Build the project\npio run\n\n# Upload to device\npio run --target upload\n\n# Monitor serial output\npio device monitor\n```\n\n#### Using VS Code with PlatformIO\n\n1. Open the project folder in VS Code\n2. Click the PlatformIO icon in the sidebar\n3. Select **Build** to compile\n4. Select **Upload** to flash the firmware\n5. Select **Monitor** to view serial output\n\n### 5. First Boot\n\nOn first boot, the device will:\n\n1. Initialize the display\n2. Connect to WiFi (may take 10-15 seconds)\n3. Synchronize time from NTP servers\n4. Display \"Binary Clock\" splash screen (1 second)\n5. Start showing binary time\n\n## Architecture Overview\n\n### Project Structure\n\n```\nbinary-clock-station/\n├── include/\n│   ├── secrets.h              # WiFi credentials (gitignored)\n│   └── secrets_template.h     # Template for secrets.h\n├── src/\n│   ├── config.h               # All configuration constants\n│   ├── BinaryClockDisplay.h   # Display class header\n│   ├── BinaryClockDisplay.cpp # Display rendering logic\n│   ├── ButtonController.h     # Button handling class header\n│   ├── ButtonController.cpp   # Button debouncing \u0026 callbacks\n│   └── main.cpp               # Main program orchestration\n├── lib/                       # Custom libraries (none currently)\n├── test/                      # Unit tests (none currently)\n├── platformio.ini             # PlatformIO configuration\n├── README.md                  # This file\n├── STATUS.md                  # Current project status\n├── REFACTOR_SUMMARY.md        # Code refactoring details\n└── OPTIMIZATION_APPLIED.md    # Optimization documentation\n```\n\n### Module Responsibilities\n\n#### `config.h`\n\n- Centralized configuration constants\n- Display dimensions and colors\n- Pin assignments\n- Timing parameters\n- Brightness levels\n\n#### `BinaryClockDisplay` Class\n\n**Responsibility**: Display rendering and visual management\n\n**Key Methods**:\n\n- `init()`: Initialize display hardware and pre-calculate layouts\n- `drawClock()`: Render binary clock with optional decimal display\n- `setBrightness()`: Adjust backlight brightness\n- `drawBCDDigit()`: Draw individual binary digit column\n- `drawTimeDigits()`: Draw decimal time digits\n- `clearTextArea()`: Clear text display area\n\n**Design Pattern**: Encapsulation of all display-related logic\n\n#### `ButtonController` Class\n\n**Responsibility**: Button input handling with callbacks\n\n**Key Methods**:\n\n- `init()`: Initialize button pins\n- `update()`: Poll button states (call in main loop)\n- `setTimeToggleCallback()`: Register time display toggle handler\n- `setBrightnessCallback()`: Register brightness change handler\n\n**Design Pattern**: Observer pattern with callbacks for loose coupling\n\n#### `main.cpp`\n\n**Responsibility**: System orchestration and business logic\n\n**Key Components**:\n\n- WiFi connection management\n- NTP time synchronization\n- Application state management\n- Event handling coordination\n- Main loop execution\n\n## Execution Flow\n\n### Startup Sequence\n\n```\n1. Power On / Reset\n   ↓\n2. Serial Communication Init (115200 baud)\n   ↓\n3. Display Hardware Init\n   ├─ Setup PWM for backlight\n   ├─ Initialize TFT display\n   ├─ Clear screen (black)\n   └─ Pre-calculate digit layouts\n   ↓\n4. Button Controller Init\n   ├─ Setup GPIO pins as inputs\n   ├─ Configure pull-ups\n   └─ Register callback functions\n   ↓\n5. WiFi Connection\n   ├─ Set WiFi mode to Station\n   ├─ Connect to configured network\n   └─ Wait for connection (max 15 seconds)\n   ↓\n6. NTP Time Synchronization\n   ├─ Configure timezone\n   ├─ Contact NTP servers\n   └─ Wait for valid time (max 10 seconds)\n   ↓\n7. Display Splash Screen\n   └─ Show \"Binary Clock\" for 1 second\n   ↓\n8. Enter Main Loop\n```\n\n### Main Loop Execution\n\n```\nMain Loop (executes every 100ms)\n│\n├─ 1. Update Button States\n│  └─ buttonController.update()\n│     ├─ Check GPIO 0 (time toggle)\n│     │  └─ If pressed: Call onTimeToggle()\n│     └─ Check GPIO 14 (brightness)\n│        └─ If pressed: Call onBrightnessChange()\n│\n├─ 2. Get Current Time\n│  └─ getLocalTime(\u0026timeinfo)\n│     ├─ Success: Continue\n│     └─ Failure: Show \"NTP?\" error, retry\n│\n├─ 3. Check for Time Change\n│  └─ Compare current time with last displayed time\n│     ├─ Time changed OR redraw needed?\n│     │  ├─ YES:\n│     │  │  ├─ Draw binary clock display\n│     │  │  ├─ Draw decimal time (if enabled)\n│     │  │  └─ Update state variables\n│     │  └─ NO: Skip rendering\n│     └─ Continue\n│\n└─ 4. Delay 100ms\n   └─ Prevents busy-waiting, reduces power\n```\n\n### Button Event Flow\n\n```\nGPIO 0 (BOOT Button) Pressed\n   ↓\nButton Debounce Check (200ms)\n   ↓\nValid Press Detected\n   ↓\nCall onTimeToggle() Callback\n   ↓\nToggle appState.showTimeDigits\n   ↓\nSet appState.needsRedraw = true\n   ↓\nNext loop iteration redraws display\n\n\nGPIO 14 Button Pressed\n   ↓\nButton Debounce Check (200ms)\n   ↓\nValid Press Detected\n   ↓\nCall onBrightnessChange(level) Callback\n   ↓\nIncrement brightness level (0-5, wraps)\n   ↓\nclockDisplay.setBrightness(level)\n   ↓\nAdjust PWM backlight intensity\n```\n\n### Display Rendering Flow\n\n```\ndrawClock(hour, minute, second, showDigits)\n   ↓\nExtract Digits\n├─ hours_tens = hour / 10\n├─ hours_ones = hour % 10\n├─ minutes_tens = minute / 10\n├─ minutes_ones = minute % 10\n├─ seconds_tens = second / 10\n└─ seconds_ones = second % 10\n   ↓\nFor each of 6 columns:\n   ↓\n   drawBCDDigit(value, layout)\n   │\n   ├─ Calculate LED positions\n   ├─ For each LED in column:\n   │  ├─ Check bit value (0 or 1)\n   │  ├─ Set color (white or light grey)\n   │  └─ Draw filled circle\n   └─ Next column\n   ↓\nIf showDigits enabled:\n   ↓\n   drawTimeDigits()\n   ├─ Clear text area\n   ├─ Draw decimal digits below each column\n   └─ Apply bold effect (draw twice)\n   ↓\nComplete\n```\n\n## Usage\n\n### Controls\n\n| Button | Function | Behavior |\n|--------|----------|----------|\n| **GPIO 0** (BOOT) | Toggle Time Display | Shows/hides decimal time digits below binary display |\n| **GPIO 14** (IO14) | Cycle Brightness | Cycles through 6 levels: 25 → 75 → 125 → 175 → 225 → 255 → 25... |\n\n### Reading the Binary Display\n\nThe display shows 6 columns representing: `HH : MM : SS`\n\nEach column is a vertical binary number (read from bottom to top):\n\n- Bottom dot = 1\n- Second dot = 2\n- Third dot = 4\n- Top dot = 8\n\n**Example**: Time is 14:37:52\n\n```\nColumns:  1   4   :   3   7   :   5   2\n         [ ] [0]  :  [ ] [0]  :  [ ] [0] \n         [ ] [4]     [2] [4]     [4] [2]\n         [0] [0]     [1] [2]     [1] [0]\n         [1] [0]     [0] [1]     [0] [0]\n         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n          1   4       3   7       5   2\nHours: 1 and 4 = 14 (2:00 PM)\nMinutes: 3 and 7 = 37\nSeconds: 5 and 2 = 52\n```\n\n### Default Settings\n\n- **Time Display**: OFF (hidden)\n- **Brightness**: Level 1 (25/255)\n- **Update Rate**: 10 times per second (100ms)\n\n## Configuration\n\n### Adjustable Parameters in `config.h`\n\n```cpp\n// Display appearance\n#define CLOCK_DOT_RADIUS 10        // LED dot size\n#define CLOCK_COL_WIDTH 30         // Column width\n#define CLOCK_GAP_SMALL 8          // Gap between digit pairs\n#define CLOCK_GAP_LARGE 20         // Gap between time units\n\n// Colors\n#define BG_COLOR   TFT_BLACK       // Background\n#define OFF_COLOR  0x7BEF          // \"Off\" LED color (light grey)\n#define ON_COLOR   TFT_WHITE       // \"On\" LED color\n\n// Timing\n#define TIME_UPDATE_INTERVAL_MS 100   // Loop delay\n#define BUTTON_DEBOUNCE_MS 200        // Button debounce time\n\n// Brightness levels (0-255)\nstatic const uint8_t BRIGHTNESS_VALUES[6] = {25, 75, 125, 175, 225, 255};\n\n// NTP Servers\n#define NTP_SERVER1 \"pool.ntp.org\"\n#define NTP_SERVER2 \"time.google.com\"\n```\n\n## Memory Usage\n\n```\nRAM:   14.0% (45,784 bytes / 327,680 bytes)\nFlash: 11.3% (739,545 bytes / 6,553,600 bytes)\n```\n\n## Troubleshooting\n\n### Display doesn't turn on\n\n- Check USB power supply (needs adequate current)\n- Verify `PIN_POWER` and `PIN_BACKLIGHT` definitions\n- Try increasing default brightness in `config.h`\n\n### WiFi connection fails\n\n- Verify credentials in `secrets.h`\n- Check WiFi signal strength\n- Ensure 2.4GHz WiFi (ESP32 doesn't support 5GHz)\n- Check serial monitor for error messages\n\n### Time shows \"NTP?\" error\n\n- WiFi must be connected first\n- Check firewall allows NTP (port 123 UDP)\n- Try different NTP servers in `config.h`\n- Verify internet connectivity\n\n### Buttons not responding\n\n- Check debounce time (200ms default)\n- Verify pin definitions match your board\n- Try longer press duration\n- Check serial monitor for button events\n\n### Display flickers\n\n- Shouldn't happen with optimized code\n- If it does, check `TIME_UPDATE_INTERVAL_MS` value\n- Ensure stable power supply\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\n\n- **LILYGO** - T-Display S3 hardware\n- **TFT_eSPI** - Display library\n- **ESP32Time** - Real-time clock management\n\n## Support\n\n- **Issues**: [GitHub Issues](https://github.com/sfrechette/binary-clock-station/issues)\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsfrechette%2Fbinary-clock-station","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsfrechette%2Fbinary-clock-station","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsfrechette%2Fbinary-clock-station/lists"}