|
@@ -0,0 +1,205 @@
|
|
1
|
+/*********
|
|
2
|
+ * Blinkinlove / Materix
|
|
3
|
+ * Techno-romantic jewelery based on
|
|
4
|
+ * Adafruit Feather HUZZAH boards and
|
|
5
|
+ * 4*8 NeoPixel Matrix FeatherWings
|
|
6
|
+ *********/
|
|
7
|
+
|
|
8
|
+#include "config.h"
|
|
9
|
+
|
|
10
|
+#include <Adafruit_NeoPixel.h>
|
|
11
|
+
|
|
12
|
+// Which pin on the Arduino is connected to the NeoPixels?
|
|
13
|
+// Default for the featherwing is 16, but for Huzzah it can't work
|
|
14
|
+// 15 is recommended (requires cutting 16 jumper and soldering 15)
|
|
15
|
+#define NEOPIXEL_PIN 15
|
|
16
|
+
|
|
17
|
+// How many NeoPixels are attached to the Arduino?
|
|
18
|
+#define NEOPIXEL_COUNT (4*8)
|
|
19
|
+
|
|
20
|
+Adafruit_NeoPixel strip(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
|
|
21
|
+
|
|
22
|
+#include <PGMWrap.h>
|
|
23
|
+
|
|
24
|
+int8_p heart0[8 * 4 * 3] PROGMEM = {
|
|
25
|
+ 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 116, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
26
|
+ 0, 0, 0, 64, 0, 0, 32, 0, 0, 60, 0, 0, 29, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
27
|
+ 0, 0, 0, 0, 0, 0, 125, 1, 1, 48, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
28
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
29
|
+};
|
|
30
|
+
|
|
31
|
+int8_p heart1[8 * 4 * 3] PROGMEM = {
|
|
32
|
+ 0, 0, 0, 32, 0, 0, 160, 0, 0, 0, 0, 0, 185, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
33
|
+ 0, 0, 0, 160, 0, 0, 64, 0, 0, 120, 0, 0, 58, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
34
|
+ 0, 0, 0, 0, 0, 0, 190, 1, 1, 96, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
35
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
36
|
+};
|
|
37
|
+
|
|
38
|
+void drawImage(int8_p *img) {
|
|
39
|
+ for (int i = 0; i < 8 * 4; i++) {
|
|
40
|
+ strip.setPixelColor(i, strip.Color(img[i * 3], img[i * 3 + 1], img[i * 3 + 2]));
|
|
41
|
+ }
|
|
42
|
+ strip.show();
|
|
43
|
+}
|
|
44
|
+
|
|
45
|
+#define NUM_FRAMES 9
|
|
46
|
+int8_p *frames[NUM_FRAMES] = {
|
|
47
|
+ heart1, heart1, heart0,
|
|
48
|
+ heart1, heart1, heart0,
|
|
49
|
+ heart0, heart0, heart0
|
|
50
|
+};
|
|
51
|
+
|
|
52
|
+#define DURATION_FAST 30
|
|
53
|
+#define DURATION_SLOW 300
|
|
54
|
+
|
|
55
|
+int current_frame = 0;
|
|
56
|
+unsigned long last_flip = 0;
|
|
57
|
+
|
|
58
|
+#define NUM_SCAN_PIXELS 4
|
|
59
|
+int scan_pixels[NUM_SCAN_PIXELS] = { 31, 23, 15, 7 };
|
|
60
|
+#define SCAN_FRAME_DURATION 200
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+// Zzzen vanity logo (scrolls after reset)
|
|
64
|
+int8_p zzzen[24 * 4] PROGMEM = {
|
|
65
|
+ 255, 255, 255, 255, 0, 255, 255, 255, 255, 0, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 255, 0, 0, 255,
|
|
66
|
+ 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 255, 128, 128, 255, 0, 255, 255, 0, 255,
|
|
67
|
+ 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 255, 255,
|
|
68
|
+ 255, 255, 255, 255, 0, 255, 255, 255, 255, 0, 255, 255, 255, 255, 0, 0, 255, 255, 255, 0, 255, 0, 0, 255
|
|
69
|
+};
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+void scrollZzzen(int offs) {
|
|
73
|
+ for (int y = 0; y < 4; y++) {
|
|
74
|
+ for (int x = 0; x < 8; x++) {
|
|
75
|
+ int xoffs = x+offs, level = 0;
|
|
76
|
+ if (xoffs>=0 && xoffs<24) {
|
|
77
|
+ level = zzzen[24*y+xoffs];
|
|
78
|
+ }
|
|
79
|
+ strip.setPixelColor(8 * y + x, strip.Color(0, 0, level));
|
|
80
|
+ }
|
|
81
|
+ }
|
|
82
|
+ strip.show();
|
|
83
|
+}
|
|
84
|
+
|
|
85
|
+#include "ESP8266WiFi.h"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+#define SCAN_INTERVAL 6000
|
|
90
|
+unsigned long next_scan = 0;
|
|
91
|
+
|
|
92
|
+String my_mac;
|
|
93
|
+String mate_mac;
|
|
94
|
+
|
|
95
|
+#define RSSI_NEAR -20
|
|
96
|
+#define RSSI_FAR -100
|
|
97
|
+int rssi = 0;
|
|
98
|
+bool scanning = false;
|
|
99
|
+
|
|
100
|
+// set rssi to mate's rssi (0 if not found)
|
|
101
|
+void checkScanResult(int numResults) {
|
|
102
|
+ rssi = 0;
|
|
103
|
+ if (numResults == 0) {
|
|
104
|
+ if (DEBUG) {
|
|
105
|
+ Serial.println("no networks found");
|
|
106
|
+ }
|
|
107
|
+ } else {
|
|
108
|
+ if (DEBUG) {
|
|
109
|
+ Serial.print(numResults);
|
|
110
|
+ Serial.println(" networks found");
|
|
111
|
+ }
|
|
112
|
+ for (int i = 0; i < numResults; ++i) {
|
|
113
|
+ if (mate_mac.equals(WiFi.BSSIDstr(i))) {
|
|
114
|
+ rssi = WiFi.RSSI(i);
|
|
115
|
+ break;
|
|
116
|
+ }
|
|
117
|
+ }
|
|
118
|
+ }
|
|
119
|
+ if (DEBUG) {
|
|
120
|
+ Serial.print(mate_mac);
|
|
121
|
+ if (rssi) {
|
|
122
|
+ Serial.print(" RSSI: ");
|
|
123
|
+ Serial.println(rssi);
|
|
124
|
+ } else {
|
|
125
|
+ Serial.println(" not found");
|
|
126
|
+ }
|
|
127
|
+ }
|
|
128
|
+ scanning = false;
|
|
129
|
+}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+// Show heart animation frame according to rssi)
|
|
133
|
+// If scanning: indicate that (animation if no rssi, single pixel otherwise)
|
|
134
|
+void animate(int rssi, bool scanning, unsigned long nowmillis) {
|
|
135
|
+ if (rssi) {
|
|
136
|
+ int duration = constrain(
|
|
137
|
+ map(rssi, RSSI_NEAR, RSSI_FAR, DURATION_FAST, DURATION_SLOW),
|
|
138
|
+ DURATION_FAST, DURATION_SLOW);
|
|
139
|
+ if ((nowmillis - last_flip) > duration || nowmillis < last_flip) {
|
|
140
|
+ drawImage(frames[current_frame]);
|
|
141
|
+ current_frame = (current_frame + 1) % NUM_FRAMES;
|
|
142
|
+ last_flip = nowmillis;
|
|
143
|
+ }
|
|
144
|
+ } else {
|
|
145
|
+ drawImage(heart0);
|
|
146
|
+ current_frame = 0;
|
|
147
|
+ }
|
|
148
|
+ if (scanning) {
|
|
149
|
+ if (rssi) {
|
|
150
|
+ strip.setPixelColor(scan_pixels[0], strip.Color(0, 0, 16));
|
|
151
|
+ } else {
|
|
152
|
+ int bright = (nowmillis / SCAN_FRAME_DURATION) % NUM_SCAN_PIXELS;
|
|
153
|
+ for (int i = 0; i < NUM_SCAN_PIXELS; i++) {
|
|
154
|
+ int blueness = i == bright ? 64 : i < bright ? 16 : 0;
|
|
155
|
+ strip.setPixelColor(scan_pixels[i], strip.Color(0, 0, blueness));
|
|
156
|
+ }
|
|
157
|
+ }
|
|
158
|
+ strip.show();
|
|
159
|
+ }
|
|
160
|
+}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+void setup()
|
|
164
|
+{
|
|
165
|
+ Serial.begin(115200);
|
|
166
|
+ delay(1000);
|
|
167
|
+
|
|
168
|
+ strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
|
|
169
|
+ strip.setBrightness(32); // (max = 255)
|
|
170
|
+ strip.show(); // Turn OFF all pixels ASAP
|
|
171
|
+
|
|
172
|
+ for (int offs = -23 ; offs < 25; offs++) {
|
|
173
|
+ scrollZzzen(offs);
|
|
174
|
+ delay(100);
|
|
175
|
+ }
|
|
176
|
+
|
|
177
|
+ my_mac = WiFi.softAPmacAddress();
|
|
178
|
+ if (DEBUG) {
|
|
179
|
+ Serial.print("My MAC: ");
|
|
180
|
+ Serial.println(my_mac);
|
|
181
|
+ }
|
|
182
|
+ if (my_mac.equals(HERS)) {
|
|
183
|
+ mate_mac = String(HIS);
|
|
184
|
+ } else {
|
|
185
|
+ mate_mac = String(HERS);
|
|
186
|
+ }
|
|
187
|
+ WiFi.softAP(String("blinkinlove:") + my_mac.substring(12), "whereartthou");
|
|
188
|
+
|
|
189
|
+}
|
|
190
|
+
|
|
191
|
+void loop()
|
|
192
|
+{
|
|
193
|
+ unsigned long nowmillis = millis();
|
|
194
|
+ if (nowmillis > next_scan) {
|
|
195
|
+ if (DEBUG) {
|
|
196
|
+ Serial.print("Scanning for ");
|
|
197
|
+ Serial.println(mate_mac);
|
|
198
|
+ }
|
|
199
|
+ scanning = true;
|
|
200
|
+ WiFi.scanNetworksAsync(checkScanResult);
|
|
201
|
+ next_scan = nowmillis + SCAN_INTERVAL;
|
|
202
|
+ }
|
|
203
|
+ animate(rssi, scanning, nowmillis);
|
|
204
|
+ delay(20);
|
|
205
|
+}
|