Rotary Dial

ESP32 firmware that reads a pulse-generating telephone rotary dial and publishes the dialled number to Home Assistant over MQTT.

Built on the ESP32 Device Framework.

How it works

A classic rotary telephone dial generates a burst of pulses as it returns to rest after each digit — one pulse for 1, two for 2, …, nine for 9, ten for 0. The firmware counts those pulses on a single GPIO pin and assembles digits into a string. When the user stops dialling (2.5 s silence), the complete number is published to MQTT.

Leading zeros are preserved: dialling 07 sends "07", not "7".

Hardware

Item Details
MCU ESP32 (any variant)
Dial Pulse-generating rotary telephone dial
Pulse pin GPIO 4 (DIAL_PIN in main.cpp)
Wiring Pulse contact between GPIO 4 and GND. Pin uses INPUT_PULLUP.

The pulse contact is normally open. As the dial returns it briefly shorts GPIO 4 to GND on each pulse — the rising edge (release) is what the interrupt counts.

If your dial's contact is normally closed instead, change the interrupt trigger in setup() from RISING to FALLING.

Building and flashing

# Build (S3 DevKit)
pio run -e esp32-s3-devkitc-1

# Flash
pio run -e esp32-s3-devkitc-1 --target upload

# Serial monitor (115200 baud)
pio device monitor

First-time Wi-Fi setup

On first boot the device opens an access point named Rotary-Dial. Connect with any phone or laptop; a captive portal will appear.

  1. Enter your Wi-Fi credentials.
  2. Optionally set the Device hostname (default: rotary-dial).
  3. Save. The device joins your network and restarts.

Reachable at http://rotary-dial.local or the IP shown in the serial monitor.

Factory reset

Power-cycle or press EN 5 times in quick succession (before boot completes). All settings are cleared and the device restarts into the Wi-Fi portal.

Web UI

Browse to the device address to configure hostname, authentication, and MQTT.

MQTT

Topics

Direction Topic Description
Published <prefix>/dialed Complete dialled number as a string (not retained)
Published <prefix>/status online on connect, offline as LWT (retained)

Default prefix: dial

Home Assistant

On MQTT connect the device publishes a discovery payload so HA automatically creates a sensor entity (sensor.<hostname>_dialed_number) that shows the last dialled number.

Example automation:

automation:
  - alias: Act on dialled number
    trigger:
      platform: mqtt
      topic: dial/dialed
    action:
      - choose:
          - conditions:
              - condition: template
                value_template: "{{ trigger.payload == '112' }}"
            sequence:
              - service: notify.mobile_app
                data:
                  message: "Emergency number dialled!"

Timing constants

Adjust in main.cpp if your dial runs faster or slower than standard:

Constant Default Description
PULSE_DEBOUNCE_MS 15 ms Minimum time between counted edges
INTER_PULSE_MS 350 ms Silence after last pulse = digit complete
INTER_DIGIT_MS 2500 ms Silence after last digit = number complete
S
Description
ESP32 firmware for a pulse-generating rotary telephone dial with HA MQTT integration
Readme 118 KiB
Languages
C++ 100%