Browse Source

Initial commit

master
The Dod 1 year ago
commit
16d2f3b783
6 changed files with 232 additions and 0 deletions
  1. 3
    0
      .gitignore
  2. 13
    0
      README.md
  3. BIN
      blinkinlove-materix-alone.gif
  4. BIN
      blinkinlove-materix.gif
  5. 205
    0
      blinkinlove-materix.ino
  6. 11
    0
      config-example.h

+ 3
- 0
.gitignore View File

@@ -0,0 +1,3 @@
1
+config.h
2
+*.swp
3
+*.backup

+ 13
- 0
README.md View File

@@ -0,0 +1,13 @@
1
+### Blinkinlove Materix
2
+
3
+_Blinkinlove_ (_אהיבהוב_) is a line of technoromantic jewlery by [zzzen](https://zzzen.com): these accessories come in pairs, and each can blink in order to indicate that it can sense whether its mate is nearby and how close it is (by performing a wifi or bluetooth scan, depending on the model) and blink accordingly.
4
+
5
+The _Materix_ model is built on an [Adafruit Feather HUZZAH](https://www.adafruit.com/product/2821) board with a 4X8 [Neopixel Matrix Featherwing](https://www.adafruit.com/product/2945).
6
+
7
+It displays a heart image that pulsates in a heartbeat rhythm when it detects its mate (heartbeat is faster the closer the mate is).
8
+
9
+![Blinkinlove Materix when close to mate](blinkinlove-materix.gif)
10
+
11
+Whenever it perfoms a scan, there's a blue indication on the right hand side. When the mate is nearby, it's a single pixel, but when the mate can't be found, this becomes a more elaborate "where art thou" animation.
12
+
13
+![Blinkinlove Materix desperately seeking mate](blinkinlove-materix-alone.gif)

BIN
blinkinlove-materix-alone.gif View File


BIN
blinkinlove-materix.gif View File


+ 205
- 0
blinkinlove-materix.ino View File

@@ -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
+}

+ 11
- 0
config-example.h View File

@@ -0,0 +1,11 @@
1
+#define DEBUG true
2
+
3
+// [If you haven't done so already] copy config-example.h to config.h
4
+
5
+// When DEBUG is true, board's MAC address is printed to serial
6
+// Once you copy MAC addresses of both mates, use them as HIS/HERS below.
7
+// You can then upload the same code to both mates (each would know to
8
+// scan for the other one, and not for itself).
9
+
10
+#define HIS "11:22:33:44:55:66"
11
+#define HERS "ff:ee:dd:cc:bb:aa"

Loading…
Cancel
Save