Skip to content

Instantly share code, notes, and snippets.

@vtalpaert
Created January 7, 2021 13:58
Show Gist options
  • Save vtalpaert/ad76461b1cb46f9c7d0757e9f27335ea to your computer and use it in GitHub Desktop.
Save vtalpaert/ad76461b1cb46f9c7d0757e9f27335ea to your computer and use it in GitHub Desktop.
Add a DancePad input to your home automation, helps creating cool lighting effects for parties
/*
Add your Wii Dance Dance Revolution Dance Pad Controller as an input to your home automation.
https://en.wikipedia.org/wiki/Dance_pad
For those that want an interactive RGB lights scenery, configure your homeassistant (hass.io)
to change your dancefloor's lighting according to the MQTT signals. Now you are doing your
own light show !
Hardware:
Each dance pad input is a weight sensible resistor. I replaced the original circuit board
with an Arduino Nano 33 IoT. The eight signals are read from the analog pins with internal
pullups, and the middle connection is connected to the ground. The signal quality is directly
dependant on the quality of your electric connections.
Configuration:
You should adapt the hardcoded configuration from the DancePad::begin method.
The parameters are :
- a threshold for considering an analog value as high or low
- a "p" value between 0 and 1, used in the equation : new_value = p * read_value + (1-p) * previous_value
- an activeHigh parameter to invert the logic such as high analog value is read as inactive
- a delta value to create an hysteresis effect in order to avoid spamming on/off messages at the threshold
PubSubClient library: https://github.com/knolleary/pubsubclient MIT License
WiFiNINA library: https://github.com/arduino-libraries/WiFiNINA
Tested with Arduino Nano 33 IoT
*/
#include <WiFiNINA.h>
#include <PubSubClient.h>
char ssid[] = "MY_NETWORK_NAME";
char pass[] = "WIFI_PASSWORD";
char host[] = "192.168.mqtt.host";
char clientid[] = "arduino-iot";
char username[] = "mqttUser";
char password[] = "mqttPassword";
String pubBaseTopic = "dancepad/";
long pubRate = 50; // [ms]
bool serialPlot = true; // set to true to silence all debug prints
WiFiClient wifiClient;
PubSubClient client(wifiClient);
long lastMsg = 0;
void setup_wifi()
{
delay(10);
if (!serialPlot) {
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
}
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
if (!serialPlot) {
Serial.print(".");
}
}
randomSeed(micros());
if (!serialPlot) {
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
}
void reconnect()
{
// Loop until we're reconnected
while (!client.connected())
{
if (!serialPlot) {
Serial.print("Attempting MQTT connection...");
}
// Create a random client ID
String clientId = "ArduinoClient-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str(), username, password))
{
if (!serialPlot) {
Serial.println("connected");
}
} else {
if (!serialPlot) {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
}
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void publish(String topic, int isPressed) {
// publish single char
char payLoad[1];
itoa(isPressed, payLoad, 10);
String fullTopic = pubBaseTopic + topic;
client.publish(fullTopic.c_str(), payLoad);
}
class SlowMovingAnalogValue {
// some analog pin might not work with pullups
private:
uint8_t pin_;
float threshold_;
float p_;
bool activeHigh_ = false;
bool state = false;
float delta_;
public:
float value_;
void begin(uint8_t pin, float threshold, float p, bool activeHigh = false, float delta = 1) {
pin_ = pin;
threshold_ = threshold;
p_ = p;
activeHigh_ = activeHigh;
delta_ = delta;
pinMode(pin_, INPUT_PULLUP);
};
uint8_t read() {
// keep in mind the pull-up means the pushbutton's logic is inverted
uint8_t val = analogRead(pin_);
value_ = p_ * (float) val + (1 - p_) * value_;
if (value_ > threshold_ + delta_) {
state = activeHigh_;
} else if (value_ < threshold_ - delta_) {
state = !activeHigh_;
}
return val;
};
bool isPressed() {
return state;
}
};
struct ArrowsState {
bool up;
bool down;
bool left;
bool right;
};
struct ControlsState {
bool a;
bool b;
bool plus;
bool minus;
};
class DancePad {
public:
SlowMovingAnalogValue plus_;
SlowMovingAnalogValue a_;
SlowMovingAnalogValue right_;
SlowMovingAnalogValue up_;
SlowMovingAnalogValue down_;
SlowMovingAnalogValue left_;
SlowMovingAnalogValue b_;
SlowMovingAnalogValue minus_;
ArrowsState arrows;
ControlsState controls;
void begin() {
plus_.begin(A7, 30, 0.05);
a_.begin(A6, 5, 0.05);
right_.begin(A5, 160, 0.05);
up_.begin(A4, 165, 0.05, true);
down_.begin(A3, 55, 0.05);
left_.begin(A2, 20, 0.05);
b_.begin(A1, 20, 0.05);
minus_.begin(A0, 30, 0.05);
}
void read() {
plus_.read();
a_.read();
right_.read();
up_.read();
down_.read();
left_.read();
b_.read();
minus_.read();
}
void updateArrows() {
bool updated = false;
bool up = up_.isPressed();
if (up != arrows.up) {
updated = true;
arrows.up = up;
publish("up", up);
}
bool down = down_.isPressed();
if (down != arrows.down) {
updated = true;
arrows.down = down;
publish("down", down);
}
bool left = left_.isPressed();
if (left != arrows.left) {
updated = true;
arrows.left = left;
publish("left", left);
}
bool right = right_.isPressed();
if (right != arrows.right) {
updated = true;
arrows.right = right;
publish("right", right);
}
if (updated) {
char payLoad[4];
itoa(up, &payLoad[0], 10);
itoa(down, &payLoad[1], 10);
itoa(left, &payLoad[2], 10);
itoa(right, &payLoad[3], 10);
String fullTopic = pubBaseTopic + "arrows";
client.publish(fullTopic.c_str(), payLoad);
}
}
bool updateControls() {
bool updated = false;
bool a = a_.isPressed();
if (a != controls.a) {
updated = true;
controls.a = a;
publish("a", a);
}
bool b = b_.isPressed();
if (b != controls.b) {
updated = true;
controls.b = b;
publish("b", b);
}
bool plus = plus_.isPressed();
if (plus != controls.plus) {
updated = true;
controls.plus = plus;
publish("plus", plus);
}
bool minus = minus_.isPressed();
if (minus != controls.minus) {
updated = true;
controls.minus = minus;
publish("minus", minus);
}
return updated;
}
}
dance = DancePad();
void setup()
{
Serial.begin(115200);
dance.begin();
setup_wifi();
client.setServer(host, 1883);
}
void loop()
{
if (!client.connected())
{
reconnect();
}
client.loop();
long now = millis();
// note that reading in the loop() is time dependant,
// so the p parameter is adapted to this tempo
dance.read();
if (now - lastMsg > pubRate)
{
lastMsg = now;
dance.updateArrows();
dance.updateControls();
}
if (serialPlot) {
Serial.print(" v = ");
// Change here to visualize another input
Serial.println(dance.up_.value_);
}
delay(2);
}
@hasghaier
Copy link

Nice !!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment