diff --git a/Button.h b/Button.h
new file mode 100644
index 0000000000000000000000000000000000000000..898fec8a675cb900762155447348bd3d872a0ced
--- /dev/null
+++ b/Button.h
@@ -0,0 +1,150 @@
+#ifndef BUTTON_h
+#define BUTTON_h
+
+class Button {
+
+  private:
+    int _pin;
+    int _id;
+
+    bool _state;
+
+    volatile bool _inputFlag = false;
+    bool _changeFlag = false;
+
+    bool _pressedFlag = false;
+    bool _holdFlag = false;
+
+    unsigned long _previousTimer;
+
+    int _clickInterval = 1000;
+    int _holdInterval = 1000;
+    int _repeatInterval = 1000;
+
+    void (*_cb)(Button*, uint8_t, bool); // Callback function
+
+    bool _read() {
+      return digitalRead(_pin);
+    }
+
+    void _setClickInterval(int x) {
+      _clickInterval = x;
+    }
+
+    void _setHoldInterval(int x) {
+      _holdInterval = x;
+    }
+
+    void _setRepeatInterval(int x) {
+      _repeatInterval = x;
+    }
+
+  public:
+
+    // Public members:
+
+    static const uint8_t kEventPressed = 0;        // Button was pressed
+    static const uint8_t kEventReleased = 1;       // Button was released
+    static const uint8_t kEventClicked = 2;        // Button was clicked (pressed and released within _clickInterval)
+    static const uint8_t kEventHeld = 3;    // Button was held down for longer than _holdInterval
+    static const uint8_t kEventTick = 4;  // Event released every _repeatInterval when button held
+
+    // Public functions:
+
+    Button(int pin, int id = 99) : _pin(pin), _id(id) {
+      pinMode(_pin, INPUT_PULLUP);
+
+      _state = _read();
+
+      _previousTimer = millis();
+    }
+
+    void initInterrupts(void(*function)()) {
+      attachInterrupt(_pin, function, CHANGE);
+    }
+
+    void setEventHandler(void(*function)(Button*, uint8_t, bool)) {
+      _cb = function;
+    }
+
+    bool getState() {
+      return _state;
+    }
+
+    int getId() {
+      return _id;
+    }
+
+    int getClickInterval() {
+      return _clickInterval;
+    }
+
+    int getHoldInterval() {
+      return _holdInterval;
+    }
+
+    int getRepeatInterval() {
+      return _repeatInterval;
+    }
+
+    void check() {
+      unsigned long timer = millis();
+      unsigned long deltaTime = timer - _previousTimer;
+      _state = _read();
+
+      if (_inputFlag == true) {
+        _inputFlag = false;
+
+        // Button pressed
+        if (_state == LOW
+            && _pressedFlag == false) {
+          _pressedFlag = true;
+          _previousTimer = timer;
+          _cb(this, kEventPressed, _state);
+          return;
+
+        // Button clicked
+        } else if (_state == HIGH
+                  && deltaTime < _clickInterval
+                  && _holdFlag == false) {
+          _pressedFlag = false;
+          _previousTimer = timer;
+          _cb(this, kEventClicked, _state);
+          return;
+
+        // Button released
+        } else if (_state == HIGH) {
+          _pressedFlag = false;
+          _holdFlag = false;
+          _previousTimer = timer;
+          _cb(this, kEventReleased, _state);
+          return;
+        }
+      }
+
+      // Button held
+      if (_state == LOW
+          && deltaTime > _holdInterval
+          && _holdFlag == false) {
+        _holdFlag = true;
+        _previousTimer = timer;
+        _cb(this, kEventHeld, _state);
+        return;
+
+      // Button tick
+      } else if (_state == LOW
+                && deltaTime > _repeatInterval
+                && _holdFlag == true) {
+        _previousTimer = timer;
+        _cb(this, kEventTick, _state);
+        return;
+      }
+    }
+
+    void ICACHE_RAM_ATTR tick() {
+      _inputFlag = true;
+    }
+
+};
+
+#endif
diff --git a/NameDictionary.h b/NameDictionary.h
index 218cde6b187048c82704677729adfdd41fd41adb..199fabc33b5a15f98e22e903847282ad3e89b7b6 100644
--- a/NameDictionary.h
+++ b/NameDictionary.h
@@ -8,7 +8,7 @@ typedef struct {
 
 class NameDictionary {
 
-  keyValuePair data[2] = {
+  keyValuePair data[50] = {
     {"1a6b16", "joe"},
     {"2b7c27", "cat"}
   };
diff --git a/RotaryEncoder.h b/RotaryEncoder.h
index 99abaea96fa36563ff78232baf3db7ae5679ab88..1b6901f6c696e84e9f3fa3e81ca644ff888a58d1 100644
--- a/RotaryEncoder.h
+++ b/RotaryEncoder.h
@@ -136,7 +136,7 @@ class RotaryEncoder {
       setPosition(0);
     }
 
-    void initInterupts(void(*function)()) {
+    void initInterrupts(void(*function)()) {
       attachInterrupt(_pinA, function, CHANGE);
       attachInterrupt(_pinB, function, CHANGE);
     }
diff --git a/examples/.DS_Store b/examples/.DS_Store
deleted file mode 100644
index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000
Binary files a/examples/.DS_Store and /dev/null differ
diff --git a/examples/EventButton/EventButton.ino b/examples/EventButton/EventButton.ino
new file mode 100644
index 0000000000000000000000000000000000000000..111909262d84440d2905c1aaba2f7c733117134b
--- /dev/null
+++ b/examples/EventButton/EventButton.ino
@@ -0,0 +1,57 @@
+#include "Button.h"
+
+const int pin = 2;
+const int ID = 0;
+
+Button b(pin, ID);
+
+void ICACHE_RAM_ATTR ISR() {
+  b.tick();
+}
+
+void setup() {
+  // put your setup code here, to run once:
+  Serial.begin(115200);
+  b.initInterrupts(ISR);
+  b.setEventHandler(cb);
+  delay(500);
+  
+  Serial.println("\n\nESP8266 Button Test:");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  b.check();
+}
+
+void cb(Button* button, uint8_t eventType, bool state) {
+  /*
+   * Rotary Encoder event handler that triggers WallVis behaviours
+   */
+   
+  String idString = String(button->getId());
+
+  Serial.println("Button ID: " + idString + " Event Type: " + String(eventType) + " State: " + String(state));
+
+  switch(eventType) {
+    case Button::kEventPressed:
+    //Do something
+    break;
+    
+    case Button::kEventReleased:
+    //Do something else
+    break;
+
+    case Button::kEventClicked:
+    //Do something else
+    break;
+
+    case Button::kEventHeld:
+    //Do something else
+    break;
+
+    case Button::kEventTick:
+    //Do something else
+    break;
+  }
+}
diff --git a/examples/EventPotentiometer/EventPotentiometer.ino b/examples/EventPotentiometer/EventPotentiometer.ino
new file mode 100644
index 0000000000000000000000000000000000000000..0b051060802eedb47538f6ac07042cac2864a484
--- /dev/null
+++ b/examples/EventPotentiometer/EventPotentiometer.ino
@@ -0,0 +1,40 @@
+#include "Potentiometer.h"
+
+const String device_id = String(ESP.getChipId(), HEX);
+
+const int sensorPin = A0;
+
+Potentiometer pot(sensorPin, 0);
+
+void setup() {
+  Serial.begin(115200);
+  pot.setEventHandler(cb);
+  delay(500);
+
+  Serial.println("\n\nESP8266 Potentiometer Test");
+  Serial.println("\nThis is board: " + device_id + "\n");
+}
+
+void loop() {
+  pot.check();
+}
+
+void cb(Potentiometer* potentiometer, uint8_t eventType, uint8_t sensorValue) {
+  /*
+   * Potentiometer Event Handler that triggers WallVis behaviours
+   */
+  
+  String idString = String(potentiometer->getId());
+
+  Serial.println("Slider ID: " + idString + " Event Type: " + String(eventType) + " Sensor Value: " + String(sensorValue));
+
+  switch(eventType) {
+    case Potentiometer::kEventStableUpdate:
+    //Do something
+    break;
+    
+    case Potentiometer::kEventUnstableUpdate:
+    //Do something else
+    break;
+  }
+}
diff --git a/examples/EventRotaryEncoder/EventRotaryEncoder.ino b/examples/EventRotaryEncoder/EventRotaryEncoder.ino
new file mode 100644
index 0000000000000000000000000000000000000000..299366f79480d90cdfc6698f7dd01f728414c9a1
--- /dev/null
+++ b/examples/EventRotaryEncoder/EventRotaryEncoder.ino
@@ -0,0 +1,45 @@
+#include "RotaryEncoder.h"
+
+const int pinA = 4;
+const int pinB = 5;
+const int ID = 0;
+
+RotaryEncoder re(pinA, pinB, ID);
+
+void ICACHE_RAM_ATTR ISR() {
+  re.tick();
+}
+
+void setup() {
+  // put your setup code here, to run once:
+  Serial.begin(115200);
+  re.initInterrupts(ISR);
+  re.setEventHandler(cb);
+  delay(500);
+  
+  Serial.println("\n\nESP8266 Rotary Encoder Test:");
+}
+
+void loop() {
+  re.check();
+}
+
+void cb(RotaryEncoder* rotaryEncoder, uint8_t eventType, int position) {
+  /*
+   * Rotary Encoder event handler that triggers WallVis behaviours
+   */
+   
+  String idString = String(rotaryEncoder->getId());
+
+  Serial.println("Encoder ID: " + idString + " Event Type: " + String(eventType) + " Position: " + String(position));
+
+  switch(eventType) {
+    case RotaryEncoder::kEventStableUpdate:
+    //Do something
+    break;
+    
+    case RotaryEncoder::kEventUnstableUpdate:
+    //Do something else
+    break;
+  }
+}
diff --git a/examples/IdLookUpStruct/IdLookUpStruct.ino b/examples/IdLookUpStruct/IdLookUpStruct.ino
new file mode 100644
index 0000000000000000000000000000000000000000..2901af67405c25e170c922e7155d49800263940e
--- /dev/null
+++ b/examples/IdLookUpStruct/IdLookUpStruct.ino
@@ -0,0 +1,29 @@
+#include "NameDictionary.h"
+
+const String device_id = String(ESP.getChipId(), HEX);
+String name;
+
+NameDictionary d;
+
+void setup() {
+  // put your setup code here, to run once:
+  Serial.begin(115200);
+
+  Serial.println("\n\nESP8266 ID Look Up Test");
+  Serial.println("Device ID: " + device_id);
+
+  String name = d.get(device_id);
+
+  if (name == "null") {
+    name = device_id;
+    Serial.print("!!! This device doesn't have a name yet. Let's call it: " + name);
+  } else {
+    Serial.print("Device name: " + name);
+  }
+  
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+
+}