ESP8266 Peripherals: KY-040 Rotary Encoder

ESP32 Development Board WiFi+Bluetooth Ultra-Low Power Consumption Dual Cores ESP-32 ESP-32S Board
Integrated antenna and RF balun, power amplifier, low-noise amplifiers, filters, and power management module. The entire solution takes up the least amount of printed circuit board area. This board is used with 2.4 GHz dual-mode Wi-Fi and Bluetooth chips by TSMC 40nm low power technology, power and RF properties best, which is safe, reliable, and scalable to a variety of applications.

The ESP8266 took the hearts of the IoT and Do-It-Yourself community by storm, due the very attractive price, its internet connectivity and due to the relatively rich amount of available GPIO pins. But an internet connected device is not worth much without means to interact with the real world. Thanks to standardised communication protocols like I2C, SPI and serial interface and the work of the Arduino community there are many sensors and actors available for a really good price. But do they play well with the ESP8266? In this series of blog posts I will share my experience with these modules and how you can use them.

The start makes an input device which is surprisingly low tech but offers a nice way to adjust settings on a display without using too much of your valuable GPIO pins: the KY-040 rotary encoder

KY-040 Rotary Encoder


What is a Rotary Encoder?

At first glance you might mistake the KY-040 for an adjustable resistor, a potentiometer. It has a knob which you can turn. But unlike real potentiometers the KY-040 can turn round and round without ever getting to a blocking limit. When turning the KY-04 you will also feel certain positions where the encoder will slide into. A potentiometer on the other hand can usually be turned smoothly until you get to the end stop. And there is another difference: the KY-040 (like most rotary encoders) has a switch which can be closed when pressing the knob vertically to the rotation axis. I have seen rotary encoders like this being used in modern radios or in built-in car navigation systems. The advantage is that they can be used relatively easy in a digital system as opposed to an analog/digital converter (ADC) reading the values from a potentiometer. There you also might have to deal with temperature drift and similar ugly problems. So in many ways a rotary encoder is the younger (millennial/digital) brother of a potentiometer.


How do you use  a Rotary Encoder?

There are different types of rotary encoders. Some can determine the absolute position/angle of the knob without constantly keeping track of its movements. But the KY-040 a very simple minded fellow. By tracking the signals on two pins an MCU can determine if the knob was turned to the left or to the right. With a third pin the state of the knob button can be tracked. The wave form on the two rotation pins looks more or less like this:

Rotary Encoder Wave Form. Picture from []
When turning the knob clockwise the signal on line B will first go high, before line A will also have a rising edge. Followed by a falling edge on line B and later by a falling edge on line A. The sequence from one click position to the next is then 00, 01, 11, 10, 00. For a counter clockwise movement the order is 00, 10, 11, 01, 00. Hence by tracking these signals carefully you can determine the direction of the rotation and also track 4 intermediate states between two clicks. If you have interrupts available you can have your code get some notification about a change of the signals on the two lines. If you don’t have interrupts available you’ll have to trust that your reading the signals often enough to not miss any important change of the signal (AKA polling the signals). And there is yet another complication: we are living in an imperfect world (in case you haven’t noticed that yet, that’s the bloody truth;-)). The mechanical contacts inside the KY-040 might “missfire” from time to time. Maybe there is some dust on the contacts or the copper has a tiny dent. However, your MCU might get a dirty signal unlike the one depicted above and draw wrong conclusions. This is where debouncing comes in. You can debounce buttons and rotary encoders like the KY-040 either in hardware or in software. The hardware solution is to use a tiny condensator to smoothen the signal from the noise a bit. But by applying a time frame where you’d expect changes to happen you can also filter out the noise pretty well. The library we will use here does that under the hood and we don’t have to worry about it. I just wanted to point out this fact so that you can understand why you might miss states occasionally and that you have to deal with that fact in your application.



Lets get our hands dirty!

Now to a practical example. Wire up your encoder like this the following picture, make sure that you follow the labels and not the ordering, I might have turned something upside down:

Wiring of the KY-040 with the NodeMCU
  • GND to GND
  • + to 3.3V
  • SW to D3
  • DT to D2
  • CLK to D1


Installing the library

There are different libraries that might work. This library worked well for me: Download the ZIP and unpack it into your Arduino library directory. Restart the Arduino IDE and copy the code from here:

#include <Encoder.h>

Encoder myEnc(D1, D2);

long oldPosition  = -999;
boolean isButtonPressed = false;
long lastUpdateMillis = 0;

void handleKey() {
  isButtonPressed = true;  

void setup() {
  Serial.println("Basic Encoder Test:");
   pinMode(D3, INPUT_PULLUP);
   attachInterrupt(D3, handleKey, RISING);

void loop() {
  long newPosition =;
  if (newPosition != oldPosition) {
    oldPosition = newPosition;
  // software debounce
  if (isButtonPressed &amp;&amp; millis() - lastUpdateMillis &gt; 50) {
    isButtonPressed = false;
    lastUpdateMillis = millis();
    // Reset the counter

After uploading the sketch you can open the serial console, turn the knob up and down and press the axis to reset the counter. Your output might look something like this:

Basic Encoder Test:
0 - Knob pressed
0 - Knob pressed


Suggested applications

  • WeatherStation Frame Controller: Some readers were asking me how they could control the currently displayed frame of the WeatherStation. Depending on the amount of the frames you are using it might take a while until the one that interests you the most comes around. The rotary encoder is a nice extension which allows you to quickly zap through the frames without having to implement a lot of code
  • Wifi Selector for unprotected APs: lets assume you have a setup with an ESP8266, a display and you want to quickly select an unprotected wifi to connect to without using the web interface: just implement some kind of menu and use the rotary encoder to move a cursor from one SSID to the next and the knob button to select the AP you actually want to connect to


Where to buy?

As always I recommend to order it from my favourite Chinese retailer Banggood

Posted by squix78


  1. Hello Dani,
    cool thing and a rather fascinating story! If I did not already have one kit I would order one…
    But one thing: On the label stuck on the bag is written “NodeMCU V3” but in the text description you write “NodeMCU V1”.
    Perhaps you can sync this?
    Best regards and successful business!

  2. Hi Daniel;

    Awesome! I got my kit and I loaded up the WeatherStation sketch and everything was working 🙂

    I then went on to add the DHT11 code and that’s when things stopped working. I suspect the firmware was over written or something bad … bricked I suspect.

    From the Arduino IDE …

    warning: espcomm_send_command: didn’t receive command response
    warning: espcomm_send_command(FLASH_DOWNLOAD_BEGIN) failed
    error: espcomm_upload_mem failed
    error: espcomm_upload_mem failed

    I then went on to try and reflash the NodeMCU firmware using ESP8266Flasher.exe … from there I get ..

    Note:Serial port connected.
    Note:Begin find ESP8266.
    Note:ESP8266 ACK success.
    Note:ESP8266 ACK success.
    Error:Set ESP8266 Address timeout.

    Similar problems directly from the esptool

    c:\Python27\Scripts> –port com5 write_flash -fm dio 0x00000 nodemcu_integer_0.9.5_20150318.bin v1.2.1

    A fatal error occurred: Timed out waiting for packet header

    … in fiddling around the board is alive .. it does send this out the serial port at 75K baud… could it be a baud rate issue? I assume not as I understand it’s autobaud detecting.

    ets Jan 8 2013,rst cause:2, boot mode:(3,7)

    Questions –

    o Do you have any suggestions on next steps?

    o Could it be power? I gather power is important for FTDI boards but the NodeMCU has the 3v3 regulator and it’s running off a PC with “good” USB current .. and it did work fine before it did not 😉

    o I’ve had no success in pressing the RST and FLASH buttons — I as I understand them, the RST/CTS lines put the board into to bootloader mode at any rate .. thoughts?

    … thoughts?

    1. Hi David

      Here sone thoughts
      – try another USB cable, the can be reason for your symptoms
      – try another USB port or restart your PC (or Mac?) I had situations where my Mac would only show the device after a restart
      – unplug the DHT11. Maybe your wiring is wrong and you accidentally switched VCC and Ground. Not sure about the longterm effects of such a switch. Such a switch was actually the only way I could ever brick an ESP8266

      If these tips don’t help feel free to get back to me

      Cheers, Dani

      1. Thanks Daniel —

        I’ve tried multiple USB cables and multiple USB ports (Windows).

        I did go back to just the bare board .. no display and no DHT11.

        I’m now trying to see it the ESP AT command set even works … and no luck there yet. I do get this when I press the reset button so it is alive a least a bit 😉

        ets Jan 8 2013,rst cause:2, boot mode:(3,7)

        but nothing in response to AT ….


        Cheers David

        1. According to this post it might have to do something with your reset pin:
          I’m not sure what that means;-).
          With which baud rate are you trying to flash the ESP? I your example from your last comment you did auto-sensing, right? Try to use a fixed lower rate like like 115200 or 57600. It often is something like the “-b” parameter.

          When you say you went back to the AT firmware: so did you manage to flash the AT firmware? After flashing the ESP8266 with the new firmware the AT binary has been replaced…

  3. Thanks Daniel — I just received another NodeMCU board as I’ve wasted enough time on the dead one 😉 If I manage to get the dead one working again, I’ll let you know.

    HNY, David

  4. Thanks Daniel, You sent me a trial kit and I purchased 2 others from Amazon. Some minor problems (outlined in Bryan Miller’s comments on Amazon). it works great but I still could use a fix to be able to get the screen to reverse from top to bottom your current variable didn’t work.

    I also located a free case plan that I had 3D printed and it fits and looks good. I found a local printer and picked it up today ($9) and it was a good fit, BUT the pins to hold the OLED were slightly out of register. I think I’ll have to cut them off and tape or glue the display in place. There is a ledge for it to fit in so i don’t think that will be a problem. I’m going to get another one printed for my local (Grand Rapids , MI USA) and I sent the plans off to my son in Atlanta, GA USA for him to use. I built the Squix kit with them over our Thanksgiving Holiday and now it will have a much better case than the plastic box it came in. Thanks for your good work and I did send off a tip. This case fits the slightly smaller SQUIX version of ESP8266 -12E. for the plans

  5. I have my kit, and am following the directions, but even after 4 cable swaps, verifying all setting from the getting started guide, and checking my IDE for errors, I cannot seem to get a valid up load.

    The error I encounter is espcomm_upload_mem failed;

    Now I verified that the chip on the board shows a CP2102, so that is the USB driver I installed;
    I restarted my computer (windows 10) to ensure driver is loaded;
    I see a com3 show up when I apply power with the USB cable, so that is the port i chose;
    I loaded the libraries as indicated, and select the board nodeMCU 1.0

    I also updated from the 1.6 to the 1.8 arduino IDE too;

    I am lost to what else I can do to get the base sketch uploaded?

    1. Hi. From distance it indeed sounds like you did everything fine. On one hand it is a good sign that the COM port shows up is a very good sign, it means that you have the correct driver installed. On the other hand there are reports of problems with the CP2102 on Windows 10. Could you check please if you have the latest driver? See these forum posts:
      Feel free to contact me again if that should not solve the problem, please also let me know if it does so I can adjust the instructions…


      1. Daniel,

        I did download from that site the latest drivers, then I un-installed and re-installed just to be safe. That did not cure it, but I also think you have pointed me in the right direction, I duplicated the installation on an adjacent windows 10 computer and have the same result. Both computers can reach an Arduino UNO with no problem (from the same USB port), so I will continue to explore the device drivers. Thanks for your response! Once I resolve this, I will advise you for your documentation.



        1. Daniel, happy to report that the drivers with Windows 10were fine. Unfortunately the nodeMCU appears to be bad. I ordered a couple more of these and they came in todays’ mail; I plugged one in to the windows 10 system and it fired right up tonight. Now I can add the sensor and the oled and play, woo-hoo!

          Thanks again for your quick response!

          Kentucky, USA

  6. Only ever been using 8266 as a wifi board for an arduino. This sounds much more interesting.
    I really want to buy your handy box, but I live in Sweden. Any chance of finding way for us Europeans?

    1. Hi again,
      I now noticed that you also had your own shop. Order is now completed. Please disregard the above. Thanks.

    1. Very nice. I was hoping that the winds could be included and looks like you nailed it with an arrow and value. Still waiting for my color display in the mail so can’t wait to see how it works.

    2. Am having trouble compiling your code, keep getting the following error:
      Arduino: 1.8.1 (Windows 10), Board: “NodeMCU 1.0 (ESP-12E Module), 160 MHz, 115200, 4M (3M SPIFFS)”

      Build options changed, rebuilding all
      C:\Users\Danny\Documents\Weather Station Bodmer\esp8266-weather-station-color-masterbodmer\esp8266-weather-station-color-master\esp8266-weather-station-color\esp8266-weather-station-color.ino:44:58: fatal error: TFT_ILI9341_ESP.h: No such file or directory

      #include // Hardware-specific library


      compilation terminated.

      exit status 1
      Error compiling for board NodeMCU 1.0 (ESP-12E Module).

      This report would have more information with
      “Show verbose output during compilation”
      option enabled in File -> Preferences.

      I have all the libraries loaded, but still cannot determine why I am getting this compile error. I have set up the display wiring according to your example.

      1. Bodmer thanks for your post on the fork of Daniel weather station color. I must have had some garbage in my IDE folder, have corrected the problem and have your version up and running. Thanks again to you and Daniel.

  7. Hi, there! considering the shortage on IL9431 display (even Banggood) and some vendors sending IL9225 (176×220) to anyone, is someone worked/working or willing to work on porting the code to use such display even sacrificing some graphic features? I can start to work from zero but my time availability is so short that to the time of progress it will be too late or other more thrilling things will be out there.

    1. This is an issue introduced with an update to the Adafruit ILI9341 library I believe. Try reverting back to a previous version (1.0.2 worked I think). I ran into this a month or so ago and it took the better part of a day to track it down. The issue may have been fixed recently, but I haven’t tried the most recent release of the library.

  8. Funny. I just two boards of which I think are ESP-01s. I can’t understand the comment about shorts in a breadboard. Their 8-pin connectors have 2.54mm or 0.1″ pitch. So they’ll fit well into a common breadboard.

  9. I uploaded the World Clock demo an hour ago and noticed at 10:30pm CDT it was showing New York time as 15:30. What caused this? Where is the time zone (+ or – hours from UTC, and DST enable/disable) information set? Now as I type this at 11:40pm, it is now showing NY time as 00:40. What happened to correct the NY time (I assume the other world times were and still are correct)?

  10. Hello, I’ve tried the trick to power the screen through the digital pin and I’ve run into trouble : my wemos was not able to communicate by serial link anymore. Moreover, the final size is so small that the USB cable is heavier than it and I’ve difficulties to maintain the whole assembly on my desk, turned to my direction.

Leave a Reply