Rotary Phone Home Control

In our house old rotary phones are used as a remote for Sonos, Philips Hue and to ring the door bell. Turning the dial on one of the phones starts playing an MP3 on the phone. Turning the dial of the phone in another room dims the light, or turns it on or off.

We use an old Ericofoon, a red and green Dutch T65:

I connected the 2 pins of the phones to an ESP8226 (nodemcu). You can buy them for cheap on Chinese webshops.

The C code below is counting pulses. I used platformio to compile the ESP8226 code and upload it. The ESP8226 requests a Raspberry Pi to evaluate an URL. The Python code for the Raspberry Pi will be subject of another post.

/* DHT */
# define DHTTYPE DHT11
# define DHTPIN D2

DHT dht(DHTPIN, DHTTYPE);

const char* ssid = "mywifi";
const char* password = "blackmirr0r";

/* LED */
Chrono chrono_led; 
int    pin_led = D4; // LED_BUILTIN
int    state_led = LOW;

/* Rotary All */
enum   enum_state {DOWN_FIRST, UP, DOWN};

/* server */
ESP8266WebServer server(80);

void log(int dial, int elapsed, int state)
{
   if (state == 0)
   {
      Serial.printf("dial=%5d, elapsed=%5d, state=DOWN_FIRST\n", dial, elapsed);
   }
   else if (state == 1)
   {
      Serial.printf("dial=%5d, elapsed=%5d, state=UP\n", dial, elapsed);
   }
   else
   {
      Serial.printf("dial=%5d, elapsed=%5d, state=DOWN\n", dial, elapsed);
   }
}

void call_server(int device, int dial)
{
   HTTPClient http;
   int httpCode;
   char url[128];

   sprintf(url, "http://192.168.1.11:8002/casa/index.php?action=dial&dial=%d&device=%d", dial, device);
   Serial.println(url);
 
   http.begin(url);

   httpCode = http.GET(); // httpCode will be negative on error
   if (httpCode > 0)
   {
      if (httpCode == HTTP_CODE_OK)
      {
         String payload = http.getString();
         Serial.println(payload);
      }
   } 
   else
   {
      Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
   }

   http.end();
}

void loop_blink_led()
{
   if (state_led == LOW)
   {
      if (chrono_led.elapsed() > 1000)
      {
         state_led = HIGH;
         digitalWrite(pin_led, state_led);
         chrono_led.restart();
      }
   }
   else
   {
      if (chrono_led.elapsed() > 10000)
      {
         state_led = LOW;
         digitalWrite(pin_led, state_led);
         chrono_led.restart();
      }
   }
}

class Rotary
{
   public:
      Rotary(int, int, double, double);
      void setup();
      void loop();
      void print();
   private:
      Chrono chrono_rotary; 
      int    pin_in  = D6;
      int    device;
      int    previous_value; 
      double period_min = 25; // in ms; minimum duration of a high 
      double period_max = 80; // in ms; maximum duration of a full period (1 high + 1 low)
      int    dial = 0;
      enum_state state = DOWN_FIRST;
};

Rotary::Rotary(int d, int pin, double pmin, double pmax)
{
   pin_in = pin;
   period_min = pmin;
   period_max = pmax;
   device = d;
};

void Rotary::setup()
{
   pinMode(pin_in, INPUT_PULLUP);
   chrono_rotary.restart();
};

void Rotary::loop()
{
   int val;
   val = digitalRead(pin_in);
   
   switch(state)
   {
      case DOWN_FIRST:
         if (val == HIGH)
         {
            state = UP;
            log(dial,chrono_rotary.elapsed(),state);
            chrono_rotary.restart();
         }
         break;
      
      case UP:
         if (val == LOW)
         {
            if (chrono_rotary.elapsed() > period_min)
            {
               state = DOWN;
               dial++;
               log(dial,chrono_rotary.elapsed(),state);
               chrono_rotary.restart();
            }
            else
            {
               state = DOWN_FIRST;
               log(dial,chrono_rotary.elapsed(),state);
            }
         }
         break;

      case DOWN:
         if (chrono_rotary.elapsed() > period_max)
         {
            state = DOWN_FIRST;
            log(dial,chrono_rotary.elapsed(),state);
            call_server(device, dial);
            dial = 0;
         }
         else if ((val == HIGH) && (chrono_rotary.elapsed() > period_min))
         {
            state = UP;
            log(dial,chrono_rotary.elapsed(),state);
            chrono_rotary.restart();
         }
         break;
   }      
};
void Rotary::print()
{
   int val;
   val = digitalRead(pin_in);
   if (previous_value != val)
   {
      Serial.printf("val=%5d, elapsed=%5d\n", val, chrono_rotary.elapsed());
      chrono_rotary.restart();
      previous_value = val;
   }
}   

Rotary T65_red  (11, D6, 25, 80);
Rotary ericofoon(13, D7, 1, 130);

void setup() {
   Serial.begin(9600);
   Serial.println("T65 Rotary");
   
   T65_red.setup();
   ericofoon.setup();
   
   pinMode(pin_led, OUTPUT);
   chrono_led.restart();
      
   WiFi.mode(WIFI_STA);
   WiFi.begin(ssid, password);
   while (WiFi.waitForConnectResult() != WL_CONNECTED) {
      Serial.println("Connection Failed! Rebooting...");
      delay(5000);
      ESP.restart();
   }

   Serial.println("Ready");
   Serial.print("IP address: ");
   Serial.println(WiFi.localIP());
   
   dht.begin();
   
   server.on("/", [](){
      String buf = "";
      float rh = dht.readHumidity();
      float temp = dht.readTemperature();
      // buf = "T=" + String(temp) + ",RH=" + String(rh);
      buf = String(temp) + "," + String(rh);
      Serial.println(buf);
      server.send(200, "text/plain", buf);
      state_led = LOW;
      digitalWrite(pin_led, state_led);
      delay(1000);
      state_led = HIGH;
      digitalWrite(pin_led, state_led);
   });
   server.begin();
}

void loop()
{
   server.handleClient();
   T65_red.loop();
   delay(0.1);
}

Leave a Reply

Your email address will not be published. Required fields are marked *