Wemos + rotary dial encoder

A project log for Vintagephone - old rotary phone retrofitting

An open project to bring new functionalities to vintage phones with the nice old rotary, keeping their fascinating vintage style alive.

giulio-ponsGiulio Pons 05/06/2022 at 15:100 Comments

After the handset the rotary encoder disc is the most fascinating part of the old phones.

The disc allows the user to compose a sequence of  numbers, each time you rotate the disc - which is a normally closed circuit - and release it, it will rotate back to its starting position and it will mechanically open a switch that make electric pulses. We can detect and count these pulses to determine each digit dialed.

To count those pulses we have to connect two outcoming wires from the rotary encoder. In my Italian SIP model there are four wires, but we need just two: one wire should be connected to GND and the other one to a pin of our board to read incoming pulses. Here is the schema. The rotary dial is a normally closed circuit so the D8 pin of Wemos read 0 because it's connected to ground throught a 330 Ohm resistor.

When a number is dialed, for example 3, the rotary open and close the switch 3 times, and the D8 pin reads three pulses of 1 because of the 5 Volts throught the series of the two resistors.

On the Arduino forum I've found a discussion about the rotary encoder that points to this link with a function readNumber that correctly counts those pulses.

In this video you can see pulses in the Arduino IDE plotter.

You can try to plot the pulses with this code:

int in = D8;

void readNumber() {
  int needToPrint = 0;
  int count=0;
  int lastState = LOW;
  int trueState = LOW;
  long lastStateChangeTime = 0;
  int cleared = 0;
  // constants
  int dialHasFinishedRotatingAfterMs = 100;
  int debounceDelay = 10;

  int digits = 0;

  unsigned long nodialingtime = 4000 ;
  unsigned long lasttimernothing = millis() + nodialingtime;

  while( digits < 10 && millis() < lasttimernothing) {

    int reading = digitalRead(in);
    if ((millis() - lastStateChangeTime) > dialHasFinishedRotatingAfterMs) {
      // the dial isn't being dialed, or has just finished being dialed.
      if (needToPrint) {
        // if it's only just finished being dialed, we need to send the number down the serial
        // line and reset the count. We mod the count by 10 because '0' will send 10 pulses.
        //Serial.println(count % 10, DEC);
        needToPrint = 0;
        count = 0;
        cleared = 0;
        lasttimernothing = millis() + nodialingtime;
    if (reading != lastState) {
      lastStateChangeTime = millis();
    if ((millis() - lastStateChangeTime) > debounceDelay) {
        // debounce - this happens once it's stablized
        if (reading != trueState) {
         // this means that the switch has either just gone from closed->open or vice versa.
         trueState = reading;
         if (trueState == HIGH) {
          // increment the count of pulses if it's gone high.
          needToPrint = 1; // we'll need to print this number (once the dial has finished rotating)
    lastState = reading;

void setup()
  pinMode(in, INPUT);

void loop()
 readNumber() ;


The script is included in the repository on Github.