-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsecret_knock.ino
160 lines (121 loc) · 3.2 KB
/
secret_knock.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Piezo sensor input pin.
const int SENSOR_PIN = A0;
const int INDICATOR_LED = LED_BUILTIN;
const int ON = HIGH;
const int OFF = LOW;
const int BLUE_PIN = 2;
const int GREEN_PIN = 3;
const int RED_PIN = 4;
const int TOTAL_COLORS = 3;
const int LEDS[TOTAL_COLORS] = {RED_PIN, GREEN_PIN, BLUE_PIN};
// Input must be above this to be registered as a valid knock.
const int THRESHOLD = 10;
// Last read knock value.
int sensorValue = 0;
// Knock readings.
const int MAX_KNOCKS = 15;
int knockReadings[MAX_KNOCKS];
// Secret knock.
const int SECRET_KNOCK[MAX_KNOCKS] = {50, 25, 25, 50, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Debounce.
const int DEBOUNCE = 150;
// Stop listening if there is no knock for END_OF_KNOCK milliseconds.
const int TIME_TO_WAIT = 1500;
// Error sway.
const int ERROR_ALLOWED = 25;
void setup()
{
Serial.begin(9600);
pinMode(INDICATOR_LED, OUTPUT);
}
void loop()
{
sensorValue = analogRead(SENSOR_PIN);
turnOnLed(BLUE_PIN);
if (isKnock(sensorValue)) {
// Start listening for a knocks.
startListening();
}
}
// Is knock actually knock enough?
bool isKnock(int input)
{
return input > THRESHOLD;
}
void startListening()
{
// Notify about listening.
Serial.println("Got the first knock...");
// Reset readings.
int i = 0;
for (i = 0; i < MAX_KNOCKS; i++)
knockReadings[i] = 0;
int knockCounter = 0;
int lastKnockTime = millis();
int now = millis();
delay(DEBOUNCE);
// Keep reading knocks.
do {
sensorValue = analogRead(SENSOR_PIN);
if (isKnock(sensorValue)) {
now = millis();
knockReadings[knockCounter++] = now - lastKnockTime;
lastKnockTime = now;
digitalWrite(INDICATOR_LED, ON);
delay(DEBOUNCE);
digitalWrite(INDICATOR_LED, OFF);
}
now = millis();
} while ((now - lastKnockTime) < TIME_TO_WAIT);
Serial.println("Finished listening for knocks, now verifying...");
for (i = 0; i < MAX_KNOCKS; i++) {
Serial.print(knockReadings[i]);
Serial.print(", ");
}
Serial.println("");
if (validateKnock()) {
Serial.println("Knock matches, welcome!");
turnOnLed(GREEN_PIN);
} else {
Serial.println("Knock did not match, go away!");
turnOnLed(RED_PIN);
}
delay(2000);
}
bool validateKnock()
{
int i, knockCount = 0, secretKnockCount = 0;
int maxKnockInterval = 0;
// Count knocks.
for (i = 0; i < MAX_KNOCKS; i++) {
if (knockReadings[i] > 0)
knockCount++;
if (SECRET_KNOCK[i] > 0)
secretKnockCount++;
if (knockReadings[i] > maxKnockInterval)
maxKnockInterval = knockReadings[i];
}
// Do knock counts match?
if (knockCount != secretKnockCount)
return false;
int timeError, totalTimeError = 0;
for (i = 0; i < MAX_KNOCKS; i++) {
knockReadings[i] = map(knockReadings[i], 0, maxKnockInterval, 0, 100);
// Serial.println(knockReadings[i]);
timeError = abs(knockReadings[i] - SECRET_KNOCK[i]);
if (timeError > ERROR_ALLOWED)
return false;
totalTimeError += timeError;
}
if (totalTimeError / secretKnockCount > ERROR_ALLOWED) {
return false;
}
return true;
}
void turnOnLed(int color)
{
for (int i = 0; i < TOTAL_COLORS; i++) {
digitalWrite(LEDS[i], LOW);
}
digitalWrite(color, HIGH);
}