-
1Step 1
The first step to building these devices, was to assemble the remote circuit, which is comprised of an ESP, an OLED, and a couple of buttons.
When creating this circuit, one can either use solder to make the connections between the different pins of the components, jumper wires, or both. Follow the diagram to create the remote circuit. The battery can be tucked on the underside of the perfboard.
The code running on this circuit creates a little menu on the OLED, where the user can control the light therapy lights and glasses. In order to navigate the menu, the user uses the 3 main buttons (topmost is to move up on the menu, middle is to confirm highlighted selection, bottom is to move down on the menu). The button on the far right of the circuit, is used to wake the ESP from sleep mode, the mode is used to conserve battery on the remote.
-
2Step 2
After creating the remote circuit, the glasses circuit can be created. This is the easiest circuit to build as it has the least components. The ESP in this circuit is connected to an LED and that is essentially the entire circuit. The reason behind this circuit's simplicity, is that it is made to fit on the user's glasses, so it has to be small and light. A small Li-Po is used in order to fit on the glasses, and when placing the circuit on the glasses, the LED is placed in the corner of the lense on the glasses. The reason behind this placement is to provide light stimulus while also not being too distracting for the user.
-
3Step 3
The final step to creating these interconnected devices, is the creation of the light/ lamp circuit. This circuit employs high power LEDs that the ESP cannot source the current for, so the [majority of the] power comes from the 3V 3A AC adapter. The PNP transistor exists to allow for high power switching (control) of the lights, by the ESP which receives commands from the remote. PLEASE MAKE SURE TO UNPLUG THE AC ADAPTER WHILE BUILDING THE CIRCUIT, AS THE HIGH POWER OUTPUT CAN KILL YOU. The red and black lines coming off of the circuit schematic connect to the anode and cathode of the AC adapter respectively.
Update:
In the new circuit, I got rid of the Li-Po battery creating a separate power supply for the ESP due to the AC adapter being able to provide power for the LEDs and the ESP. The new circuit now has the ESP sharing a power supply with the LEDs, which means there is no need for a Li-Po and the entire circuit is smaller and can be powered by just plugging in the AC adapter.
-
4Step 4
Now that all the required circuits are finished, their corresponding programs can be uploaded onto the ESP boards.
Code for remote circuit:
//#include <TimeLib.h> #include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <ESP8266WiFi.h> //#include <ArduinoOTA.h> //#include "Adafruit_MQTT.h" //#include "Adafruit_MQTT_Client.h" #include "OLEDDisplayUi.h" //#include "images.h" #include <Wire.h> #include "SSD1306.h" SSD1306 display(0x3c, 4, 5); const char* ssid = "ULtrafast Network"; //COW_Wireless const char* password = "AdellarIran"; //JHSW1F1! const char* host = "192.168.4.1"; int pos = 1; int page = 0; //0 = main, 1 = on/off 2, brightness, 3 = sleep int sel = 12; int up = 14; int down = 13; int ledState = 0; int lightState = 0; int btnUp = 0; int btnDown = 0; int btnSel = 0; int upClicked = 0; int downClicked = 0; int selClicked = 0; bool selBrightness = false; int brightness = 0; bool select = false; unsigned long Clock = 0; unsigned long brTime = 0; bool storeBr = false; int storedBr = 0; //static bool select = false; WiFiClient client; //OLEDDisplayUi ui ( &display ); int screenW = 128; int screenH = 64; int clockCenterX = screenW/2; int clockCenterY = ((screenH-16)/2)+16; // top yellow part is 16 px height int clockRadius = 23; /* // utility function for digital clock display: prints leading 0 String twoDigits(int digits){ if(digits < 10) { String i = '0'+String(digits); return i; } else { return String(digits); } } void clockOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) { } void analogClockFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { // ui.disableIndicator(); // Draw the clock face // display->drawCircle(clockCenterX + x, clockCenterY + y, clockRadius); display->drawCircle(clockCenterX + x, clockCenterY + y, 2); // //hour ticks for( int z=0; z < 360;z= z + 30 ){ //Begin at 0° and stop at 360° float angle = z ; angle = ( angle / 57.29577951 ) ; //Convert degrees to radians int x2 = ( clockCenterX + ( sin(angle) * clockRadius ) ); int y2 = ( clockCenterY - ( cos(angle) * clockRadius ) ); int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 8 ) ) ) ); int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 8 ) ) ) ); display->drawLine( x2 + x , y2 + y , x3 + x , y3 + y); } float angle = second() * 6 ; angle = ( angle / 57.29577951 ) ; //Convert degrees to radians int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 5 ) ) ) ); int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 5 ) ) ) ); display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y); // display minute hand float angle = minute() * 6 ; angle = ( angle / 57.29577951 ) ; //Convert degrees to radians int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 4 ) ) ) ); int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 4 ) ) ) ); display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y); // // display hour hand angle = hour() * 30 + int( ( minute() / 12 ) * 6 ) ; angle = ( angle / 57.29577951 ) ; //Convert degrees to radians x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 2 ) ) ) ); y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 2 ) ) ) ); display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y); } void digitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { String timenow = String(hour())+":"+twoDigits(minute())+":"+twoDigits(second()); display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(ArialMT_Plain_24); display->drawString(clockCenterX + x , clockCenterY + y, timenow ); } FrameCallback frames[] = { analogClockFrame, digitalClockFrame }; int frameCount = 2; OverlayCallback overlays[] = { clockOverlay }; int overlaysCount = 1; */ /*void watch(){ int remainingTimeBudget = ui.update(); if(remainingTimeBudget > 0){ delay(remainingTimeBudget); if(select == true){ menu(); } } }*/ void menu(){ display.clear(); display.flipScreenVertically(); display.setFont(ArialMT_Plain_16); display.setTextAlignment(TEXT_ALIGN_LEFT); display.clear(); display.drawString(47,0, "Menu"); display.drawHorizontalLine(0,18,128); display.setFont(ArialMT_Plain_10); display.drawString(53,20, "Glasses"); display.drawString(51,30, "Sleep"); display.drawString(51,40, "Lights"); display.drawString(50,50, "Screen"); display.drawRect(0, (10*pos)+12, 10, 8); display.fillRect(0, (10*pos)+12, 10, 8); //display.drawString(10, 128, String(millis())); // write the buffer to the display display.display(); } void Glasses(){ display.clear(); display.drawString(37, 0, "LED Control"); display.drawString(20, 20, "LED is: "); if (ledState == 0){ display.drawString(60, 20, "OFF"); } else{ display.drawString(60, 20, "ON 40Hz"); } display.drawString(20, 40, "LED Brightness"); if(selBrightness == false){ display.setFont(ArialMT_Plain_10); display.drawString(0, 52, "Back"); } if(pos == 1 && selBrightness == false){ display.drawRect(0, (pos*10) + 12, 10, 8); display.fillRect(0, (pos*10) + 12, 10, 8); } if(pos == 2 && selBrightness == false){ display.drawRect(0, (pos*10) + 22, 10, 8); display.fillRect(0, (pos*10) + 22, 10, 8); } if(pos == 3 && selBrightness == false){ display.drawRect(25, (pos*19), 12, 5); display.fillRect(25, (pos*19), 12, 5); } if(/*pos >= 2 &&*/ selBrightness == true){ if(storeBr == true){ pos = storedBr; Serial.print(" Storedpos : "); Serial.println(pos); storeBr = false; } else{ pos = pos; Serial.print(" pos : "); Serial.println(pos); } if(pos <= -5){ pos = -5; } else{ if(pos > 0){ pos = 0; } } brightness = -pos; storedBr = pos; display.drawProgressBar(10, 55, 80, 5, brightness * 20 ); if(select == true && brTime < Clock){ selBrightness = false; pos = 2; } } display.display(); } void Sleep(){ display.displayOff(); display.end(); ESP.deepSleep(100000, WAKE_RF_DEFAULT); //delay(100); //Serial.println("hi"); ESP.reset(); } void Lights(){ display.clear(); display.drawString(37, 0, "Light Control"); display.drawString(20, 20, "Light is: "); if (lightState == 0){ display.drawString(60, 20, "OFF"); } if(lightState == 1){ display.drawString(60, 20, "ON 40Hz"); } if(lightState == 2){ display.drawString(60, 20, "ON Constant"); } display.drawString(20, 40, "Light Brightness"); if(selBrightness == false){ display.setFont(ArialMT_Plain_10); display.drawString(0, 52, "Back"); } if(pos == 1 && selBrightness == false){ display.drawRect(0, (pos*10) + 12, 10, 8); display.fillRect(0, (pos*10) + 12, 10, 8); } if(pos == 2 && selBrightness == false){ display.drawRect(0, (pos*10) + 22, 10, 8); display.fillRect(0, (pos*10) + 22, 10, 8); } if(pos == 3 && selBrightness == false){ display.drawRect(25, (pos*19), 12, 5); display.fillRect(25, (pos*19), 12, 5); } if(/*pos >= 2 &&*/ selBrightness == true){ if(storeBr == true){ pos = storedBr; Serial.print(" Storedpos : "); Serial.println(pos); storeBr = false; } else{ pos = pos; Serial.print(" pos : "); Serial.println(pos); } if(pos <= -5){ pos = -5; } else{ if(pos > 0){ pos = 0; } } brightness = -pos; storedBr = pos; display.drawProgressBar(10, 55, 80, 5, brightness * 20 ); if(select == true && brTime < Clock){ selBrightness = false; pos = 2; } } display.display(); } void setup() { display.init(); display.displayOn(); display.clear(); display.flipScreenVertically(); Serial.begin(115200); display.drawString(DISPLAY_WIDTH/2 - 10, DISPLAY_HEIGHT/2, "Booting"); display.display(); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); display.clear(); display.drawString(DISPLAY_WIDTH/2 - 20, DISPLAY_HEIGHT/2, "WiFi connected"); display.display(); delay(500); pinMode(up, INPUT); pinMode(down, INPUT); pinMode(sel, INPUT); pinMode(up, INPUT_PULLUP); pinMode(down, INPUT_PULLUP); pinMode(sel, INPUT_PULLUP); display.clear(); display.setFont(ArialMT_Plain_16); display.setTextAlignment(TEXT_ALIGN_LEFT); display.clear(); display.drawString(47,0, "Menu"); display.drawHorizontalLine(0,18,128); display.setFont(ArialMT_Plain_10); display.drawString(50,20, "Glasses"); display.drawString(51,30, "Sleep"); display.drawString(51,40, "Lights"); display.drawString(50,50, "Screen"); display.drawRect(0, (10*pos)+12, 10, 8); display.fillRect(0, (10*pos)+12, 10, 8); //display.drawString(10, 128, String(millis())); // write the buffer to the display display.display(); /*ui.setTargetFPS(30); ui.setActiveSymbol(activeSymbol); //ui.setInactiveSymbol(inactiveSymbol); //ui.setIndicatorPosition(TOP); ui.setIndicatorDirection(LEFT_RIGHT); ui.setFrameAnimation(SLIDE_LEFT); ui.setFrames(frames, frameCount); ui.setOverlays(overlays, overlaysCount); ui.init(); unsigned long secsSinceStart = millis(); // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: unsigned long epoch = secsSinceStart - seventyYears * SECS_PER_HOUR; setTime(epoch);*/ } void loop() { WiFiClient client; Clock = millis(); select = false; if (page == 0){ menu(); } if (page == 1){ Glasses(); } if (page == 2){ //Sleep(); } if (page == 3){ Lights(); } if (btnUp == 1 && digitalRead(up) == HIGH){ upClicked = 1; btnUp = 0; pos = pos -1; //Serial.println("up"); } if (btnDown == 1 && digitalRead(down) == HIGH){ downClicked = 1; btnDown = 0; pos= pos +1; //Serial.println("down"); } if (btnSel == 1 && digitalRead(sel) == HIGH){ selClicked = 1; btnSel = 0; select = true; if(client.connect(host, 80) && selBrightness == true){ if(pos != 0){ if(pos == -1){ client.print(String("/led/1")); } if(pos == -2){ client.print(String("/led/2")); } if(pos == -3){ client.print(String("/led/3")); } if(pos == -4){ client.print(String("/led/4")); } if(pos == -5){ client.print(String("/led/5")); } } } } if (digitalRead(up) == LOW){ btnUp = 1; Serial.println("up"); } if (digitalRead(down) == LOW){ btnDown = 1; Serial.println("down"); } if (digitalRead(sel) == LOW){ btnSel = 1; Serial.println("select"); } if (pos == 3 && select == true && page == 0){ Lights(); pos = 1; page = 3; } if (pos == 1 && select == true && page == 0){ Glasses(); pos = 1; page = 1; } else{ if (pos == 3 && select == true && page == 1){ menu(); pos = 1; page = 0; } if (pos == 3 && select == true && page == 3){ menu(); pos = 1; page = 0; } if(pos == 2 && select == true && page == 0){ page = 0; //ESP.reset(); Sleep(); } /* else{ if(page == 2 && select == true){ page = 0; menu(); pos = 1; } }*/ if(pos == 1 && select == true && page == 1){ Glasses(); if(ledState == 0){ if(client.connect(host, 80)){ client.print(String("/led/ON")); ledState = 1; } } else{ if(client.connect(host, 80)){ client.print(String("/led/OFF")); ledState = 0; } } } if(pos == 1 && select == true && page == 3){ Lights(); if(lightState == 0){ if(client.connect(host, 80)){ client.print(String("/light/ON")); lightState = 1; } } if(lightState == 1){ if(client.connect(host, 80)){ client.print(String("/light/OFF")); lightState = 2; } } if(lightState == 2){ if(client.connect(host, 80)){ client.print(String("/light/CONST")); lightState = 0; } } } if(pos <= 2 && select == true && page == 1 && selBrightness == true){ storeBr = true; selBrightness = false; pos = 2; Glasses(); } else{ if(pos == 2 && select == true && page == 1 && selBrightness == false){ selBrightness = true; brTime = millis(); Glasses(); /*if(storedBr != 0){ pos = 0; }*/ } } } }
Code for Glasses circuit:
#include <ESP8266WiFi.h> const char WiFiAPPSK[] = "AdellarIran"; int activeTime = 0; unsigned long CurrentTime = 0; unsigned long offTime = 0; unsigned long millsPerHour = 3600000; unsigned long savedTime = 0; int state = LOW; int LEDmode = 0; int LEDbr = 1023; bool constant = false; WiFiServer server(80); void Light(bool state){ const char* host = "192.168.4.1"; WiFi.disconnect(); WiFi.mode(WIFI_STA); WiFi.begin("Light", "AdellarIran"); while(WiFi.status() != WL_CONNECTED){ delay(500); Serial.print("."); } WiFiClient client; if(client.connect(host, 80)){ if(constant == true){ client.print(String("/light/CONST")); Serial.println("Sent Light constant"); } else{ if(state){ client.print(String("/light/ON")); Serial.println("Sent Light on"); } else{ client.print(String("/light/OFF")); Serial.println("Sent Light off"); } } } } void AcessP(){ WiFi.disconnect(); WiFi.mode(WIFI_AP); setupWiFi(); server.begin(); } void setup() { initHardware(); setupWiFi(); server.begin(); Serial.begin(9600); Serial.println("hi"); pinMode(12, OUTPUT); } void loop() { CurrentTime = millis(); WiFiClient client = server.available(); if (client){ String request = client.readStringUntil('\r'); client.flush(); if(request.indexOf("/led/ON") != -1){ LEDmode = 1; LEDbr = 1023; } if(request.indexOf("/led/OFF") != -1){ LEDmode = 1; LEDbr = 0; } if(request.indexOf("/led/1") != -1){ LEDbr= 205.8; LEDmode = 1; } if(request.indexOf("/led/2") != -1){ LEDbr= 410.1; LEDmode = 1; } if(request.indexOf("/led/3") != -1){ LEDbr= 614.4; LEDmode = 1; } if(request.indexOf("/led/4") != -1){ LEDbr= 818.7; LEDmode = 1; } if(request.indexOf("/led/5") != -1){ LEDbr= 1023; LEDmode = 1; } if(request.indexOf("/light/ON") != -1){ Serial.println("hi"); constant = false; bool state = true; Light(state); AcessP(); } if(request.indexOf("/light/OFF") != -1){ constant = false; bool state = false; Light(state); AcessP(); } if(request.indexOf("/light/CONST") != -1){ constant = true; AcessP(); } client.flush(); String s = "HTTP/1.1 200 OK\r\n"; s+= "Content-Type: text/html\r\n\r\n"; s+= "<!DOCTYPE HTML>\r\n<html>\r\n"; client.print(s); delay(1); Serial.println("Client Disconnected"); } if (LEDmode == 1){ if (CurrentTime - savedTime >= 12.5 && state == LOW){ if(LEDbr == 1023){ digitalWrite(12, HIGH); } else{ analogWrite(12, LEDbr); } savedTime = millis(); state = HIGH; } if (CurrentTime - savedTime >= 12.5 && state == HIGH){ analogWrite(12, 0); savedTime = millis(); state = LOW; } } else{ digitalWrite(12, LOW); } } void setupWiFi(){ WiFi.mode(WIFI_AP); uint8_t mac[WL_MAC_ADDR_LENGTH]; WiFi.softAPmacAddress(mac); String macID = String(mac[WL_MAC_ADDR_LENGTH - 3], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 2], HEX); String AP_NameString = "ULtrafast Network"; char AP_NameChar[AP_NameString.length() + 1]; memset(AP_NameChar, 0, AP_NameString.length() + 1); for (int i =0; i<AP_NameString.length(); i++) AP_NameChar[i] = AP_NameString.charAt(i); WiFi.softAP(AP_NameChar, WiFiAPPSK); } void initHardware() { //Serial.begin(115200); }
Code for light/lamp circuit:
#include <ESP8266WiFi.h> const char WiFiAPPSK[] = "AdellarIran"; int activeTime = 0; unsigned long CurrentTime = 0; unsigned long offTime = 0; unsigned long millsPerHour = 3600000; unsigned long savedTime = 0; int state = LOW; int LEDmode = 0; int LEDbr = 1023; WiFiServer server(80); void setup() { initHardware(); setupWiFi(); server.begin(); //Serial.begin(9600); pinMode(4, OUTPUT); digitalWrite(4, LOW); } void loop() { CurrentTime = millis(); WiFiClient client = server.available(); if (client){ String request = client.readStringUntil('\r'); client.flush(); if(request.indexOf("/light/ON") != -1){ LEDmode = 1; LEDbr = 1023; Serial.println("light ON"); } if(request.indexOf("/light/OFF") != -1){ LEDmode = 1; LEDbr = 0; Serial.println("light OFF"); } if(request.indexOf("/light/CONST") != -1){ LEDmode = 2; LEDbr = 0; Serial.println("light OFF"); } client.flush(); String s = "HTTP/1.1 200 OK\r\n"; s+= "Content-Type: text/html\r\n\r\n"; s+= "<!DOCTYPE HTML>\r\n<html>\r\n"; client.print(s); delay(1); Serial.println("Client Disconnected"); } if (LEDmode == 1){ if (CurrentTime - savedTime >= 12.5 && state == LOW){ digitalWrite(4, HIGH); savedTime = millis(); state = HIGH; } if (CurrentTime - savedTime >= 12.5 && state == HIGH){ if(LEDbr == 1023){ digitalWrite(4, LOW); } else{ digitalWrite(4, HIGH); } savedTime = millis(); state = LOW; } } else{ digitalWrite(4, LOW); } } void setupWiFi(){ WiFi.mode(WIFI_AP); uint8_t mac[WL_MAC_ADDR_LENGTH]; WiFi.softAPmacAddress(mac); String macID = String(mac[WL_MAC_ADDR_LENGTH - 3], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 2], HEX); String AP_NameString = "Light"; char AP_NameChar[AP_NameString.length() + 1]; memset(AP_NameChar, 0, AP_NameString.length() + 1); for (int i =0; i<AP_NameString.length(); i++) AP_NameChar[i] = AP_NameString.charAt(i); WiFi.softAP(AP_NameChar, WiFiAPPSK); } void initHardware() { Serial.begin(115200); }
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.