982 lines
32 KiB
Markdown
982 lines
32 KiB
Markdown
# ESPHome AiP650E Display Monitor Component Specification
|
|
## Microcontroller Proxy Architecture
|
|
|
|
**Document Version:** 3.0
|
|
**Date:** April 2026
|
|
**Target Platform:** ESP32-S3 (with optional AVR/STM32 proxy)
|
|
**Original IC:** Wuxi I-CORE AiP650E (2-line Serial Interface LED Controller/Driver)
|
|
|
|
---
|
|
|
|
## 1. Overview
|
|
|
|
This specification describes an ESPHome custom component for reading standing desk display information via a protocol proxy microcontroller. The architecture uses a small AVR or STM32 microcontroller to reliably capture the time-critical AiP650E protocol from the original desk controller, then exposes decoded display data to the ESP32-S3 via I2C.
|
|
|
|
### 1.1 Architecture Rationale
|
|
|
|
Given that the ESP32-S3 is already fully loaded with:
|
|
- High-resolution display rendering (SPI)
|
|
- Capacitive touchscreen input processing
|
|
- WiFi/BLE connectivity with background tasks
|
|
|
|
A dedicated protocol proxy microcontroller provides:
|
|
|
|
- ✅ **Reliable timing capture** - No jitter from WiFi, rendering, or touch processing
|
|
- ✅ **Clean separation of concerns** - Timing logic isolated from UI/connectivity logic
|
|
- ✅ **Simpler integration** - ESP32 reads simple I2C data instead of complex protocol capture
|
|
- ✅ **Better real-time guarantees** - AVR/STM32 can dedicate 100% resources to protocol
|
|
- ✅ **Inexpensive** - Arduino Nano, STM32F401, etc. cost $5-15
|
|
|
|
### 1.2 System Overview
|
|
|
|
The original control board's microcontroller continues to manage motor control, height calculations via Hall sensors, and display updates. A small proxy microcontroller captures the AiP650E bus communication and makes display data available to the ESP32-S3 via I2C. The ESP32-S3 runs ESPHome with a simple I2C driver component to read display values and button states, focusing on UI rendering and Home Assistant integration.
|
|
|
|
---
|
|
|
|
## 2. System Architecture
|
|
|
|
### 2.1 Tri-Microcontroller Design (Recommended: ATtiny85 Proxy)
|
|
|
|
```
|
|
┌───────────────────────────────────────────────────────────────────┐
|
|
│ Standing Desk Control System │
|
|
└───────────────────────────────────────────────────────────────────┘
|
|
|
|
ORIGINAL MICROCONTROLLER (32-bit MCU) - Original Board
|
|
├── Function: Motor control, height calculation, display updates
|
|
├── Connected:
|
|
│ ├── H-Bridge Motor Driver (pins 1, 2, 3, 5)
|
|
│ ├── Hall Sensor Inputs (pins 11, 12, 17, 18)
|
|
│ ├── Motor Sense/Voltage Sense (pins 19, 20)
|
|
│ ├── SEGM_CLK (pin 16) ──────────┐
|
|
│ └── SEGM_DIO (pin 15) ──────────┼──→ [ATtiny85 Proxy]
|
|
│ │
|
|
└── Behavior: │
|
|
└── Sends display commands via CLK/DIO
|
|
|
|
ATtiny85 PROXY MICROCONTROLLER (8-pin DIP)
|
|
├── Function: AiP650E protocol capture & I2C bridge
|
|
├── Pin Assignment (8 pins total):
|
|
│ ├── Pin 2: PB3 ← SEGM_CLK (from original, CLK input/interrupt)
|
|
│ ├── Pin 3: PB4 ← SEGM_DIO (from original, DIO data input)
|
|
│ ├── Pin 5: PB0 → SCL (to ESP32 I2C, with 4.7k pull-up)
|
|
│ ├── Pin 6: PB1 → SDA (to ESP32 I2C, with 4.7k pull-up)
|
|
│ ├── Pin 7: PB2 (spare for future use)
|
|
│ ├── Pin 4: GND (common ground)
|
|
│ └── Pin 8: VCC (3.3V from ESP32)
|
|
└── Behavior:
|
|
├── Captures CLK/DIO protocol continuously
|
|
├── Decodes display segments in real-time
|
|
├── Exposes 7 I2C registers (0x00-0x04 + control)
|
|
└── 100% reliability (no WiFi/render jitter)
|
|
|
|
ESP32-S3 (ESPHome) - With Touchscreen
|
|
├── Function: UI rendering, touch input, WiFi, Home Assistant
|
|
├── Connected:
|
|
│ ├── Display panel (SPI) - 30+ pins
|
|
│ ├── Touch controller (I2C/SPI)
|
|
│ ├── I2C SCL (GPIO21) ← ATtiny85 (reads display data)
|
|
│ ├── I2C SDA (GPIO20) ← ATtiny85 (reads display data)
|
|
│ ├── GPIO14 ← KEY_UP (direct from original board pin 14)
|
|
│ ├── GPIO13 ← KEY_DOWN (direct from original board pin 13)
|
|
│ └── WiFi antenna (internal)
|
|
└── Behavior:
|
|
├── Renders touchscreen UI
|
|
├── Polls I2C every 100ms for display data
|
|
├── Updates Home Assistant via WiFi
|
|
├── Handles touch input & button monitoring
|
|
└── Lightweight I2C component (simple polling)
|
|
```
|
|
|
|
### 2.1a Hardware Wiring Summary
|
|
|
|
```
|
|
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
|
│ Original │ │ ATtiny85 │ │ ESP32-S3 │
|
|
│ Desk Micro │ │ Proxy │ │ (ESPHome) │
|
|
├─────────────────┤ ├──────────────────┤ ├─────────────────┤
|
|
│ Pin 16 (CLK) ──┼─→ Pin 2 (PB3) │ │ │
|
|
│ Pin 15 (DIO) ──┼─→ Pin 3 (PB4) │ │ │
|
|
│ Pin 14 (UP) ──┼──────────────────────→ GPIO14 │
|
|
│ Pin 13 (DOWN) ──┼──────────────────────→ GPIO13 │
|
|
│ │ Pin 5 (PB0/SCL) ─┬──→ GPIO21 (SCL) │
|
|
│ │ Pin 6 (PB1/SDA) ─┼──→ GPIO20 (SDA) │
|
|
│ GND ───┼─→ Pin 4 (GND) ────┼──→ GND │
|
|
│ │ Pin 8 (VCC) ◄────┼── GPIO 3.3V │
|
|
│ │ │ [4.7k pulls] │
|
|
└─────────────────┘ └──────────────────┘ └─────────────────┘
|
|
```
|
|
|
|
**Key Points:**
|
|
- ✅ Buttons (UP/DOWN) connect directly to ESP32 - no proxy involvement
|
|
- ✅ ATtiny85 focuses only on protocol capture (isolated, reliable)
|
|
- ✅ ESP32 does UI/WiFi/rendering without timing pressure
|
|
- ✅ Minimal wiring: just 4 GPIO + I2C + GND + 3.3V
|
|
|
|
AiP650E DISPLAY DRIVER
|
|
├── Status: PHYSICALLY REMOVED from board
|
|
├── Previously connected to:
|
|
│ ├── Pin 2 (CLK) ← Original Micro (now disconnected)
|
|
│ ├── Pin 3 (DIO) ← Original Micro (now disconnected)
|
|
│ └── Segments/Grids (no longer needed)
|
|
└── Replacement: ESP32-S3 software protocol decoder
|
|
```
|
|
|
|
### 2.2 Hardware Connections
|
|
|
|
```
|
|
ORIGINAL MICROCONTROLLER ESP32-S3
|
|
┌──────────────────────┐ ┌──────────┐
|
|
│ │ │ │
|
|
│ Pin 16 (SEGM_CLK) ├─────────→ GPIO_CLK │
|
|
│ Pin 15 (SEGM_DIO) ├─────────→ GPIO_DIO │
|
|
│ │ │ │
|
|
│ [Motor & Hall] │ │ [WiFi] │
|
|
│ (isolated) │ │ [Touch] │
|
|
└──────────────────────┘ └──────────┘
|
|
│ │
|
|
│ [To Touchscreen]
|
|
│
|
|
┌────┴────┐
|
|
│ Removed │
|
|
│ AiP650E │ (Physically removed from board)
|
|
│ Display │
|
|
│ Driver │
|
|
└─────────┘
|
|
|
|
BUTTONS (Shared or Duplicated)
|
|
┌──────────────┐
|
|
│ Key_Up ├─→ ESP32-S3 GPIO
|
|
│ Key_Down ├─→ ESP32-S3 GPIO
|
|
│ Mem 1 (K15) ├─→ Originally via AiP650E key matrix
|
|
│ Mem 2 (K12) ├─→ (No longer accessible - can be removed)
|
|
│ Mem 3 (K11) ├─→ (No longer accessible - can be removed)
|
|
└──────────────┘
|
|
```
|
|
|
|
### 2.3 Protocol Monitoring Role
|
|
|
|
The ESP32-S3 acts as a **passive listener** on the AiP650E communication bus:
|
|
|
|
- **Does NOT send commands** to the AiP650E
|
|
- **Does NOT interfere** with original microcontroller operation
|
|
- **Listens to** CLK/DIO signals originating from the original microcontroller
|
|
- **Decodes** display data, brightness, and mode commands
|
|
- **Extracts** segment information from data writes to RAM addresses 0x68, 0x6A, 0x6C
|
|
- **Reports** findings to ESPHome as sensors and binary sensors
|
|
|
|
This approach ensures:
|
|
- ✅ Original motor control continues unaffected
|
|
- ✅ Height sensing via Hall sensors remains intact
|
|
- ✅ Display information is available to touchscreen UI
|
|
- ✅ No conflicts or bus contention
|
|
- ✅ Simple hardware modifications (just connect two lines and buttons)
|
|
|
|
---
|
|
|
|
## 3. Protocol Monitoring & Decoding
|
|
|
|
### 3.1 2-Line Serial Interface (Listener Perspective)
|
|
|
|
The ESP32-S3 monitors a 2-line serial protocol used by the original microcontroller to communicate with the AiP650E:
|
|
|
|
- **CLK (from original micro):** Clock signal - provides timing reference
|
|
- **DIO (from original micro):** Data signal - carries command and data bytes (open-drain, pulled high by resistor)
|
|
|
|
### 3.2 Bus Monitoring Basics
|
|
|
|
**Frame Structure (as monitored):**
|
|
- Start Condition: CLK high, DIO falling edge (high → low)
|
|
- Data Phase: 8 bits + 1 ACK bit (9 bits total per byte)
|
|
- Stop Condition: CLK high, DIO rising edge (low → high)
|
|
|
|
**Timing Requirements for Listening:**
|
|
- CLK low level width: typically ≥100 ns
|
|
- CLK high level width: typically ≥100 ns
|
|
- Minimum delay to sample DIO after CLK edge: ≥30 ns (add margin in software)
|
|
- Maximum transmission rate: 0-4 Mbps (typical 1-2 Mbps for this application)
|
|
|
|
**Key Difference - Listener Role:**
|
|
- ESP32 does NOT drive CLK or DIO low (no open-drain outputs)
|
|
- ESP32 only reads CLK and DIO states as inputs
|
|
- ESP32 uses GPIO interrupts on CLK rising edges to time DIO sampling
|
|
- No need to generate ACK bit (original micro is the master)
|
|
|
|
### 3.3 Command Decoding
|
|
|
|
The ESP32 monitors and decodes instructions sent by the original microcontroller:
|
|
|
|
**Instruction Format:** All instructions are 16-bit (2 bytes) transmitted MSB first:
|
|
|
|
```
|
|
[System Instruction Byte] [Display/Control Instruction Byte]
|
|
```
|
|
|
|
**System Instruction Byte (monitoring):**
|
|
- Expected value: `0x48` (binary: `01001000`)
|
|
- If received: System is being configured
|
|
- Component logs this state
|
|
|
|
**Display Instruction Byte (monitoring):**
|
|
```
|
|
Bit Position: B7 B6 B5 B4 B3 B2 B1 B0
|
|
Display Mode: D (B0: Display on=1 / off=0)
|
|
Sleep Mode: W (B1: Sleep enable=1 / disable=0)
|
|
SEG Control: S (B3: Seven-segment=1 / eight=0)
|
|
Brightness: BR[2:0] (B5-B3: Brightness level 0-7)
|
|
```
|
|
|
|
**Monitored Parameters:**
|
|
- **Display On/Off:** Track whether display is active
|
|
- **Brightness Level:** 0=1 level, 1=2 levels, ..., 7=8 levels (standard range)
|
|
- **Display Mode:** 7-segment or 8-segment configuration
|
|
- **Sleep Mode:** Whether sleep mode is enabled
|
|
|
|
### 3.4 Display Data Monitoring
|
|
|
|
Display data is written to RAM addresses on the AiP650E. The ESP32 intercepts these writes:
|
|
|
|
**RAM Address Mapping (Monitored):**
|
|
```
|
|
Address | Data Bits (B7-B0) | Display
|
|
---------|-------------------------|---------
|
|
0x68 | A B C D E F G DP | DIG1 (leftmost/hundreds)
|
|
0x6A | A B C D E F G DP | DIG2 (middle/tens)
|
|
0x6C | A B C D E F G DP | DIG3 (rightmost/ones)
|
|
0x6E | (reserved) | DIG4 (not used for digits)
|
|
```
|
|
|
|
**Segment Decoding:**
|
|
- **A-G:** Standard 7-segment display segments (bits 0-6)
|
|
- **DP:** Decimal point (bit 7)
|
|
|
|
When the component detects writes to these addresses, it:
|
|
1. Captures the segment byte
|
|
2. Decodes which digit is shown (0-9) based on segment pattern
|
|
3. Reports the value as a sensor update
|
|
4. Stores raw segment data for debug purposes
|
|
|
|
### 3.5 Key Press Monitoring
|
|
|
|
The original microcontroller can request key data from the AiP650E. The ESP32 intercepts these requests:
|
|
|
|
**Get Key Command (monitored):**
|
|
```
|
|
Bit: B7 B6 B5 B4 B3 B2 B1 B0
|
|
Val: 0 1 0 0 1 X X 1 (0x49 with variable bits)
|
|
```
|
|
|
|
**Key Data Response Format (captured):**
|
|
```
|
|
Format: 01_BBBKKKK (8 bits data + 1 ACK bit)
|
|
- BBB: Button row (0-3 for DIG1-DIG4)
|
|
- KKK: Button column (0-7 for KI1-KI7)
|
|
- Special: 00_101_110 (0x2E) = No key pressed
|
|
```
|
|
|
|
**Memory Button Status (via AiP650E monitoring):**
|
|
|
|
| Memory Button | AiP650E Row | AiP650E Column | Expected Value |
|
|
|---------------|------------|----------------|----------------|
|
|
| Mem 1 (K15 / KI5) | DIG4 (3) | KI5 (4) | `01_011_100` |
|
|
| Mem 2 (K12 / KI2) | DIG4 (3) | KI2 (1) | `01_001_100` |
|
|
| Mem 3 (K11 / KI1) | DIG4 (3) | KI1 (0) | `01_000_100` |
|
|
| No Key | Any | - | `00_101_110` (0x2E) |
|
|
|
|
**Note:** Memory button monitoring via AiP650E is optional - direct physical button connections to ESP32 GPIO are more reliable.
|
|
|
|
**Memory Button Status (via AiP650E monitoring):**
|
|
|
|
| Memory Button | AiP650E Row | AiP650E Column | Expected Value |
|
|
|---------------|------------|----------------|----------------|
|
|
| Mem 1 (K15 / KI5) | DIG4 (3) | KI5 (4) | `01_011_100` |
|
|
| Mem 2 (K12 / KI2) | DIG4 (3) | KI2 (1) | `01_001_100` |
|
|
| Mem 3 (K11 / KI1) | DIG4 (3) | KI1 (0) | `01_000_100` |
|
|
| No Key | Any | - | `00_101_110` (0x2E) |
|
|
|
|
**Note:** Memory button monitoring via AiP650E is optional - direct physical button connections to ESP32 GPIO are more reliable for the primary up/down buttons.
|
|
|
|
---
|
|
|
|
## 4. Component Specification
|
|
|
|
### 4.1 Component Name
|
|
|
|
```yaml
|
|
display_driver_aip650e:
|
|
```
|
|
|
|
### 4.2 Configuration Parameters
|
|
|
|
```yaml
|
|
display_driver_aip650e:
|
|
# Required: CLK and DIO pin definitions (listeners, not drivers)
|
|
clk_pin: GPIO_PIN_NUMBER
|
|
dio_pin: GPIO_PIN_NUMBER
|
|
|
|
# Optional: Button GPIO pins
|
|
button_up_pin: GPIO_PIN_NUMBER # PIN 14 on original board (KEY_UP)
|
|
button_down_pin: GPIO_PIN_NUMBER # PIN 13 on original board (KEY_DOWN)
|
|
|
|
# Optional: Display monitoring interval (default: 100ms)
|
|
# How often to check for new display data from the original micro
|
|
update_interval: 100ms
|
|
|
|
# Optional: Enable button monitoring (default: true)
|
|
enable_buttons: true
|
|
|
|
# Optional: Debounce time for physical buttons (default: 50ms)
|
|
button_debounce_time: 50ms
|
|
|
|
# Optional: AiP650E protocol monitoring settings
|
|
protocol:
|
|
# Attempt to decode memory buttons from AiP650E bus (default: false)
|
|
# Set to true only if keeping original memory button hardware
|
|
monitor_memory_buttons: false
|
|
|
|
# Communication timeout (default: 1000ms)
|
|
# If no CLK edges detected for this duration, consider bus inactive
|
|
timeout: 1000ms
|
|
```
|
|
|
|
### 4.3 Exposed Sensors
|
|
|
|
#### 4.3.1 Display Value Sensor
|
|
|
|
Exposes the 3-digit height value being displayed by the original control board:
|
|
|
|
```yaml
|
|
sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Standing Desk Height Display"
|
|
id: desk_height_display
|
|
unit_of_measurement: "mm"
|
|
icon: "mdi:ruler-square"
|
|
```
|
|
|
|
**Sensor Properties:**
|
|
- **Type:** Numeric sensor
|
|
- **Range:** 0-999 (3 digits)
|
|
- **Update Rate:** Whenever the original microcontroller updates the display (typically 1-10 times per second)
|
|
- **Source:** Decoded from segment data on 0x68, 0x6A, 0x6C RAM addresses
|
|
- **Reliability:** Mirrors exactly what the original display shows
|
|
|
|
#### 4.3.2 Individual Digit Sensors
|
|
|
|
Optionally expose each digit separately:
|
|
|
|
```yaml
|
|
sensor:
|
|
- platform: display_driver_aip650e
|
|
digit: 1 # DIG1 - hundreds
|
|
name: "Desk Height - Hundreds"
|
|
|
|
- platform: display_driver_aip650e
|
|
digit: 2 # DIG2 - tens
|
|
name: "Desk Height - Tens"
|
|
|
|
- platform: display_driver_aip650e
|
|
digit: 3 # DIG3 - ones
|
|
name: "Desk Height - Ones"
|
|
```
|
|
|
|
#### 4.3.3 Segment Data Sensor (Debug)
|
|
|
|
For troubleshooting, optionally expose raw segment data:
|
|
|
|
```yaml
|
|
text_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Display Raw Segments"
|
|
id: raw_segments
|
|
```
|
|
|
|
Returns segment data as: `"DIG1: ABCDEFGDP, DIG2: ..., DIG3: ..."`
|
|
|
|
#### 4.3.4 Display Control Status (Monitored)
|
|
|
|
Optional text sensor showing monitored control states:
|
|
|
|
```yaml
|
|
text_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Display Status"
|
|
id: display_status
|
|
```
|
|
|
|
Returns: `"on/off, brightness: X, mode: 7-seg/8-seg, ..."`
|
|
|
|
---
|
|
|
|
## 5. Button Interface
|
|
|
|
### 5.1 Physical Button Sensors
|
|
|
|
The component monitors the physical KEY_UP and KEY_DOWN buttons connected directly to the ESP32 GPIO:
|
|
|
|
```yaml
|
|
binary_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "UP Button"
|
|
id: key_up
|
|
button: up # or specify: button_pin_name: up
|
|
on_press:
|
|
then:
|
|
- logger.log: "UP button pressed"
|
|
on_release:
|
|
then:
|
|
- logger.log: "UP button released"
|
|
|
|
- platform: display_driver_aip650e
|
|
name: "DOWN Button"
|
|
id: key_down
|
|
button: down
|
|
on_press:
|
|
then:
|
|
- logger.log: "DOWN button pressed"
|
|
```
|
|
|
|
**Button Characteristics:**
|
|
- **Type:** Binary sensor (pressed/released)
|
|
- **Source:** Direct GPIO connection (pins 13, 14 on original board)
|
|
- **Debounce:** Configurable (default 50ms)
|
|
- **Update Rate:** Immediate on press/release
|
|
|
|
### 5.2 Optional Memory Button Monitoring
|
|
|
|
If the original memory button hardware is retained and connected to GPIO pins, they can be monitored:
|
|
|
|
```yaml
|
|
binary_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Memory Button 1"
|
|
id: mem_button_1
|
|
button: memory_1 # Optional: alternative to GPIO-based buttons
|
|
on_press:
|
|
then:
|
|
- logger.log: "Memory 1 pressed"
|
|
|
|
- platform: display_driver_aip650e
|
|
name: "Memory Button 2"
|
|
id: mem_button_2
|
|
button: memory_2
|
|
|
|
- platform: display_driver_aip650e
|
|
name: "Memory Button 3"
|
|
id: mem_button_3
|
|
button: memory_3
|
|
```
|
|
|
|
**Note:** Memory buttons are NOT decoded from the AiP650E bus by default (unreliable). Instead, they should be wired directly to GPIO pins if needed.
|
|
|
|
### 5.3 Button Configuration
|
|
|
|
```yaml
|
|
display_driver_aip650e:
|
|
# Physical button pins
|
|
button_up_pin: GPIO14
|
|
button_down_pin: GPIO13
|
|
|
|
# Optional memory button pins (if wired to ESP32)
|
|
button_mem1_pin: GPIO_PIN # Optional
|
|
button_mem2_pin: GPIO_PIN # Optional
|
|
button_mem3_pin: GPIO_PIN # Optional
|
|
|
|
# Debouncing settings
|
|
button_debounce_time: 50ms
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Display Monitoring & Integration
|
|
|
|
### 6.1 Real-Time Display Monitoring
|
|
|
|
The component continuously monitors the AiP650E communication bus and extracts display information in real-time:
|
|
|
|
- **Segment Capture:** Intercepts writes to display RAM (0x68, 0x6A, 0x6C)
|
|
- **Digit Decoding:** Converts segment patterns to digit values (0-9)
|
|
- **State Tracking:** Monitors brightness, display on/off status
|
|
- **Update Rate:** Responds immediately to changes from original microcontroller
|
|
|
|
### 6.2 Integration with Touchscreen UI
|
|
|
|
The exposed sensors can be used to synchronize a touchscreen display with the original height information:
|
|
|
|
```yaml
|
|
# Example: Display the monitored height on touchscreen
|
|
display_runner:
|
|
- id: my_display
|
|
components:
|
|
- lambda: |-
|
|
it.printf(10, 10, id(font), "Height: %.0fmm", id(desk_height_display).state);
|
|
```
|
|
|
|
### 6.3 Home Automation Integration
|
|
|
|
Button states can trigger automations:
|
|
|
|
```yaml
|
|
automation:
|
|
- trigger:
|
|
platform: binary_sensor
|
|
id: key_up
|
|
action: press
|
|
then:
|
|
- logger.log: "User pressed UP - height increasing"
|
|
- homeassistant.service:
|
|
service: input_number.set_value
|
|
data_template:
|
|
entity_id: input_number.desk_height_setpoint
|
|
value: "{{ (states('input_number.desk_height_actual') | float(0) + 10) | round(0) }}"
|
|
```
|
|
|
|
### 6.4 Limitations & Constraints
|
|
|
|
⚠️ **Important Note:** The ESP32 component is a **passive listener only**:
|
|
- ❌ Cannot control the display (original microcontroller is the master)
|
|
- ❌ Cannot modify display values shown
|
|
- ❌ Cannot control motor directly (connected to original microcontroller)
|
|
- ✅ Can read what the original system is displaying
|
|
- ✅ Can read button inputs
|
|
- ✅ Can provide UI feedback via touchscreen
|
|
|
|
To control the motor or display, communicate with the original microcontroller via a separate interface (if available, e.g., UART, I²C).
|
|
|
|
---
|
|
|
|
## 7. Configuration Examples
|
|
|
|
### 7.1 Basic Configuration (Listener Mode)
|
|
|
|
```yaml
|
|
esphome:
|
|
name: standing-desk-controller
|
|
|
|
esp32_s3:
|
|
board: esp32-s3-devkitc-1
|
|
variant: esp32s3
|
|
|
|
# Display driver monitor component
|
|
display_driver_aip650e:
|
|
# Listen to SEGM_CLK and SEGM_DIO from original microcontroller
|
|
clk_pin: GPIO16 # Connected to original board pin 16 (SEGM_CLK)
|
|
dio_pin: GPIO15 # Connected to original board pin 15 (SEGM_DIO)
|
|
|
|
# Monitor physical buttons
|
|
button_up_pin: GPIO14 # Connected to original board pin 14 (KEY_UP)
|
|
button_down_pin: GPIO13 # Connected to original board pin 13 (KEY_DOWN)
|
|
|
|
# Update settings
|
|
update_interval: 100ms
|
|
button_debounce_time: 50ms
|
|
|
|
sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Desk Height Display"
|
|
id: desk_height_display
|
|
unit_of_measurement: "mm"
|
|
icon: "mdi:ruler-square"
|
|
|
|
binary_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "UP Button"
|
|
id: key_up
|
|
button: up
|
|
icon: "mdi:arrow-up"
|
|
|
|
- platform: display_driver_aip650e
|
|
name: "DOWN Button"
|
|
id: key_down
|
|
button: down
|
|
icon: "mdi:arrow-down"
|
|
```
|
|
|
|
### 7.2 Advanced Configuration with Touchscreen Integration
|
|
|
|
```yaml
|
|
esphome:
|
|
name: standing-desk-esp32
|
|
|
|
esp32_s3:
|
|
board: esp32-s3-devkitc-1
|
|
variant: esp32s3
|
|
psram:
|
|
mode: quad
|
|
speed: 80MHz
|
|
|
|
# Display driver monitor
|
|
display_driver_aip650e:
|
|
clk_pin: GPIO16
|
|
dio_pin: GPIO15
|
|
button_up_pin: GPIO14
|
|
button_down_pin: GPIO13
|
|
|
|
update_interval: 50ms
|
|
button_debounce_time: 75ms
|
|
|
|
protocol:
|
|
timeout: 1000ms
|
|
|
|
# Touchscreen display
|
|
spi:
|
|
clk_pin: GPIO6
|
|
mosi_pin: GPIO7
|
|
miso_pin: GPIO8
|
|
|
|
display:
|
|
- platform: ili9xxx
|
|
id: my_display
|
|
model: ILI9488
|
|
cs_pin: GPIO5
|
|
dc_pin: GPIO9
|
|
reset_pin: GPIO10
|
|
update_interval: 200ms
|
|
|
|
lambda: |-
|
|
// Display the monitored height
|
|
it.printf(160, 50, id(font_large), TextAlign::CENTER,
|
|
"Height: %.0f mm", id(desk_height_display).state);
|
|
|
|
// Show button status
|
|
if (id(key_up).state) {
|
|
it.filled_rectangle(10, 120, 300, 50, COLOR_WHITE);
|
|
it.printf(160, 145, id(font), TextAlign::CENTER, "UP PRESSED");
|
|
}
|
|
if (id(key_down).state) {
|
|
it.filled_rectangle(10, 180, 300, 50, COLOR_WHITE);
|
|
it.printf(160, 205, id(font), TextAlign::CENTER, "DOWN PRESSED");
|
|
}
|
|
|
|
sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Desk Height Display"
|
|
id: desk_height_display
|
|
unit_of_measurement: "mm"
|
|
icon: "mdi:ruler-square"
|
|
on_value:
|
|
then:
|
|
- logger.log:
|
|
format: "Display height updated to: %.0f mm"
|
|
args: ['x']
|
|
|
|
- platform: display_driver_aip650e
|
|
digit: 1
|
|
name: "Height Hundreds"
|
|
id: height_hundreds
|
|
|
|
- platform: display_driver_aip650e
|
|
digit: 2
|
|
name: "Height Tens"
|
|
id: height_tens
|
|
|
|
- platform: display_driver_aip650e
|
|
digit: 3
|
|
name: "Height Ones"
|
|
id: height_ones
|
|
|
|
text_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Display Status"
|
|
id: display_status
|
|
|
|
binary_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "UP Button"
|
|
id: key_up
|
|
button: up
|
|
on_press:
|
|
then:
|
|
- logger.log: "UP button pressed - desk moving up"
|
|
on_release:
|
|
then:
|
|
- logger.log: "UP button released"
|
|
|
|
- platform: display_driver_aip650e
|
|
name: "DOWN Button"
|
|
id: key_down
|
|
button: down
|
|
on_press:
|
|
then:
|
|
- logger.log: "DOWN button pressed - desk moving down"
|
|
on_release:
|
|
then:
|
|
- logger.log: "DOWN button released"
|
|
|
|
# Home Assistant integration
|
|
api:
|
|
encryption:
|
|
key: !secret api_key
|
|
|
|
ota:
|
|
password: !secret ota_password
|
|
|
|
wifi:
|
|
ssid: !secret wifi_ssid
|
|
password: !secret wifi_password
|
|
|
|
ap:
|
|
ssid: "DeskScreen Fallback"
|
|
password: !secret ap_password
|
|
```
|
|
|
|
### 7.3 Minimal Configuration (Monitor Only, No Buttons)
|
|
on_value:
|
|
then:
|
|
- logger.log:
|
|
format: "Display height updated to: %.0f mm"
|
|
args: ['x']
|
|
|
|
- platform: display_driver_aip650e
|
|
digit: 1
|
|
name: "Height Hundreds"
|
|
id: height_hundreds
|
|
|
|
- platform: display_driver_aip650e
|
|
digit: 2
|
|
name: "Height Tens"
|
|
id: height_tens
|
|
|
|
- platform: display_driver_aip650e
|
|
digit: 3
|
|
name: "Height Ones"
|
|
id: height_ones
|
|
|
|
text_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Display Status"
|
|
id: display_status
|
|
|
|
binary_sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "UP Button"
|
|
id: key_up
|
|
button: up
|
|
on_press:
|
|
then:
|
|
- logger.log: "UP button pressed - desk moving up"
|
|
on_release:
|
|
then:
|
|
- logger.log: "UP button released"
|
|
|
|
- platform: display_driver_aip650e
|
|
name: "DOWN Button"
|
|
id: key_down
|
|
button: down
|
|
on_press:
|
|
then:
|
|
- logger.log: "DOWN button pressed - desk moving down"
|
|
on_release:
|
|
then:
|
|
- logger.log: "DOWN button released"
|
|
|
|
# Home Assistant integration
|
|
api:
|
|
encryption:
|
|
key: !secret api_key
|
|
|
|
ota:
|
|
password: !secret ota_password
|
|
|
|
wifi:
|
|
ssid: !secret wifi_ssid
|
|
password: !secret wifi_password
|
|
|
|
ap:
|
|
ssid: "DeskScreen Fallback"
|
|
password: !secret ap_password
|
|
```
|
|
|
|
### 7.3 Minimal Configuration (Monitor Only, No Buttons)
|
|
|
|
```yaml
|
|
esphome:
|
|
name: standing-desk-monitor
|
|
|
|
esp32_s3:
|
|
board: esp32-s3-devkitc-1
|
|
|
|
display_driver_aip650e:
|
|
clk_pin: GPIO16
|
|
dio_pin: GPIO15
|
|
# Note: button pins omitted - can be added later if needed
|
|
|
|
sensor:
|
|
- platform: display_driver_aip650e
|
|
name: "Desk Height"
|
|
id: desk_height_display
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Data Structures
|
|
|
|
### 8.1 Segment Encoding
|
|
|
|
Standard 7-segment display layout:
|
|
|
|
```
|
|
AAAA
|
|
F B
|
|
GGGG
|
|
E C
|
|
DDDD DP
|
|
|
|
Bit Mapping (byte):
|
|
Bit 7: DP (decimal point)
|
|
Bit 6: G (middle segment)
|
|
Bit 5: F (top-left)
|
|
Bit 4: E (bottom-left)
|
|
Bit 3: D (bottom)
|
|
Bit 2: C (bottom-right)
|
|
Bit 1: B (top-right)
|
|
Bit 0: A (top)
|
|
```
|
|
|
|
### 8.2 7-Segment Character Set (Common)
|
|
|
|
| Char | Hex | Binary | Display |
|
|
|------|-----|--------|---------|
|
|
| 0 | 0x3F | 0011_1111 | 0 |
|
|
| 1 | 0x06 | 0000_0110 | 1 |
|
|
| 2 | 0x5B | 0101_1011 | 2 |
|
|
| 3 | 0x4F | 0100_1111 | 3 |
|
|
| 4 | 0x66 | 0110_0110 | 4 |
|
|
| 5 | 0x6D | 0110_1101 | 5 |
|
|
| 6 | 0x7D | 0111_1101 | 6 |
|
|
| 7 | 0x07 | 0000_0111 | 7 |
|
|
| 8 | 0x7F | 0111_1111 | 8 |
|
|
| 9 | 0x6F | 0110_1111 | 9 |
|
|
|
|
### 8.3 Component Internal State
|
|
|
|
```yaml
|
|
component_state:
|
|
comm_protocol:
|
|
clk_pin: GPIO number
|
|
dio_pin: GPIO number
|
|
last_clk_state: boolean
|
|
last_dio_state: boolean
|
|
comm_timeout: ms
|
|
|
|
display_state:
|
|
digit1_segments: byte (0-255)
|
|
digit2_segments: byte (0-255)
|
|
digit3_segments: byte (0-255)
|
|
brightness_level: 1-8
|
|
power_on: boolean
|
|
mode_7segment: boolean
|
|
|
|
button_state:
|
|
button1_pressed: boolean
|
|
button2_pressed: boolean
|
|
button3_pressed: boolean
|
|
debounce_counters: [0, 0, 0]
|
|
last_key_value: byte
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Implementation Notes
|
|
|
|
### 9.1 Bus Listening & Protocol Decoding
|
|
|
|
- **No Active Driving:** ESP32 only reads CLK and DIO - does not drive them low (no open-drain output)
|
|
- **GPIO Interrupt Handler:** Use CLK rising edge interrupt to trigger DIO sampling
|
|
- **Timing Accuracy:** Sample DIO on CLK rising edges with ≥30ns setup margin
|
|
- **Bit Shift Register:** Accumulate 8 bits per clock cycle, detect start/stop conditions
|
|
|
|
### 9.2 Hardware Connections
|
|
|
|
- **CLK & DIO Lines:** Connect directly from original microcontroller through appropriate level shifters (if voltage differs)
|
|
- **Voltage Levels:** If original micro is 5V and ESP32 is 3.3V, use voltage divider or level shifter for DIO input
|
|
- **Pull-ups:** CLK and DIO typically have internal or external pull-ups (10k) - no additional pull-ups needed on ESP32 side
|
|
- **Ground:** Ensure common ground between original microcontroller and ESP32
|
|
|
|
### 9.3 Display Data Extraction
|
|
|
|
- **RAM Address Monitoring:** Intercept writes to addresses 0x68 (DIG1), 0x6A (DIG2), 0x6C (DIG3)
|
|
- **Segment Decoding:** Convert captured segment bytes to 7-segment patterns, match against known digit set (0-9)
|
|
- **Timing:** Updates happen naturally as the original micro commands the display - no polling required
|
|
- **Jitter Reduction:** Debounce rapid segment changes (may indicate display refresh) before reporting state change
|
|
|
|
### 9.4 Button Input Handling
|
|
|
|
- **Physical Buttons (UP/DOWN):** Simple GPIO input with software debouncing
|
|
- **Debounce Implementation:** Wait for 2 consecutive stable readings before reporting state change
|
|
- **Debounce Duration:** Configurable, typically 50-75ms
|
|
- **Optional Memory Buttons:** If wired to GPIO, use same debounce logic
|
|
|
|
### 9.5 Edge Cases & Error Handling
|
|
|
|
- **Bus Inactivity:** If no CLK transitions for > 1 second, consider bus inactive/error
|
|
- **Partial Frames:** If data frame is incomplete, discard and wait for next frame
|
|
- **ACK Bit Handling:** Don't generate ACK (ESP32 is listener only) - just skip bit 9
|
|
- **Original Micro Disconnection:** Component gracefully handles loss of bus activity, reports "offline" status
|
|
- **Voltage Spike Protection:** Add 100nF capacitor near GPIO inputs if experiencing noise
|
|
|
|
---
|
|
|
|
## 10. Troubleshooting Guide
|
|
|
|
| Issue | Likely Cause | Solution |
|
|
|-------|-------------|----------|
|
|
| No data received | Incorrect GPIO pins | Verify GPIO16 (CLK) and GPIO15 (DIO) are set correctly in config |
|
|
| No data received | Hardware not connected | Check physical wiring: original micro pin 16→GPIO16, pin 15→GPIO15 |
|
|
| No data received | Voltage levels | If original micro is 5V, add level shifter for DIO line |
|
|
| Display values incorrect | Segment decoding error | Check 7-segment character set matches hardware (may use different convention) |
|
|
| Display updates too slow | Bus monitoring timeout too high | Reduce `update_interval` config parameter |
|
|
| Button presses not detected | Physical button wiring | Verify GPIO13/GPIO14 connected to KEY_DOWN/KEY_UP from original board |
|
|
| Intermittent display reading | Electrical noise on CLK/DIO | Add 100nF capacitor from GPIO pins to GND; check wiring length/routing |
|
|
| Bus detected but no display data | Original micro not sending | Original microcontroller may not be running; check its power and reset |
|
|
| Memory button decoding fails | AiP650E not present | Memory button monitoring requires AiP650E to be connected (currently removed) |
|
|
|
|
---
|
|
|
|
## 11. Hardware Wiring Reference
|
|
|
|
### 11.1 GPIO Connection Map
|
|
|
|
| Function | Original Board | ESP32-S3 GPIO | Notes |
|
|
|----------|----------------|---------------|-------|
|
|
| Display Clock | Pin 16 (SEGM_CLK) | GPIO16 | CLK input (read only) |
|
|
| Display Data | Pin 15 (SEGM_DIO) | GPIO15 | DIO input (read only) |
|
|
| Up Button | Pin 14 (KEY_UP) | GPIO14 | Button input (optional) |
|
|
| Down Button | Pin 13 (KEY_DOWN) | GPIO13 | Button input (optional) |
|
|
| Ground | GND | GND | Common reference |
|
|
|
|
### 11.2 Level Shifting (if needed)
|
|
|
|
If original microcontroller operates at 5V and ESP32 at 3.3V:
|
|
|
|
```
|
|
DIO Line (5V → 3.3V):
|
|
5V source → [10k Ω] → GPIO15 (3.3V max)
|
|
├→ [GND via 10k Ω]
|
|
Result: voltage divider, ~2.5V on GPIO (safe for 3.3V input)
|
|
|
|
CLK Line:
|
|
Same as DIO if switching at high frequency (>1 MHz)
|
|
Direct connection OK if clock frequency < 100 kHz
|
|
```
|
|
|
|
---
|
|
|
|
## 12. Related Documents
|
|
|
|
- **Datasheet:** AiP650E-AX-XS-B037EN (Wuxi I-CORE Electronics)
|
|
- **Reference:** 2-line Serial Interface / Common Cathode 8Seg 4Grid LED Controller/Driver
|
|
- **Hardware:** Standing Desk Control Board (Original, with AiP650E physically removed)
|
|
- **Integration:** ESP32-S3 with touchscreen UI
|
|
- **Original System:** Microcontroller (32-bit) handling motor control and Hall sensors
|
|
|
|
---
|
|
|
|
## 13. Revision History
|
|
|
|
| Version | Date | Changes |
|
|
|---------|------|---------|
|
|
| 1.0 | 2026-04-23 | Initial specification (master-driven architecture) |
|
|
| 2.0 | 2026-04-23 | Revised to listener-only architecture; ESP32 monitors bus instead of driving |
|
|
|