Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Kenneth Yang
Published © GPL3+

EUD1_Dev

Eyes-Up-Display v1, developer edition. Basically your wearable heads up display that can be used anywhere, like at home or at work.

AdvancedFull instructions provided6 hours1,440

Things used in this project

Hardware components

Male/Male Jumper Wires
These are the wires that I used in my project, feel free to change them to whatever type you want. There are even some places where I would change the wires from Male/Male to Male/Female...
×15
Female/Female Jumper Wires
Female/Female Jumper Wires
These are the wires that I used in my project, feel free to change them to whatever type you want. There are even some places where I would change the wires from Female/Female to Male/Female...
×32
DS3231 RTC module (ZS-04)
I was unable to find a retailer link for this, so here's the link I used when I bought it from Amazon
×1
Parallax MEMSIC 2125 Dual-axis Accelerometer (Mx2125)
×1
128x64 Monochrome SPI OLED
Just go to amazon.com and search for "128x64 SPI OLED" and you will be flooded with results that look exactly like this one. If you find a cheaper offer than the one listed here, by all means take it!
×1

Software apps and online services

Fusion
Autodesk Fusion
Arduino IDE
Arduino IDE
mt MediaTek Cloud Sandbox (MCS)
To relay the collected data.
Maker service
IFTTT Maker service
Used to relay information to MCS

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
To print the casing
Soldering iron (generic)
Soldering iron (generic)
There are three small custom wire joints that need a soldering iron (and solder) to join

Story

Read more

Custom parts and enclosures

Device frame

This is the .stl file for the device frame. The display is on the right side. If you want to change that, view the fusion file.

Schematics

Breadboard view

Title says it all. Made with Fritzing.

Schematic View

Title says it all. Made with Fritzing.

Code

EUD1_Dev

Arduino
Arduino Code for this device
/*
   EUD1_Dev -Arduino Code
   (v1.0)
   Developer: Microbob
   Contact: microbob@is88.com
   Libraries from: Adafruit and Arduino
*/

//Library import
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <gfxfont.h>
#include <Wire.h>
#include <SPI.h>


//OLED pin declaration
#define oledMOSI 7 //D1
#define oledCLK 8 //D0
#define oledDC 5
#define oledCS 4
#define oledRST 6

//Mx2125 (accelerometer) pin declaration
#define accX 9
#define accY 10

//DS3231 (RTC module) address
#define DS3231_I2C_ADDRESS 0x68


//OLED display setup
Adafruit_SSD1306 display(oledMOSI, oledCLK, oledDC, oledRST, oledCS);
#if (SSD1306_LCDHEIGHT != 64)
#error("height incorrect, please fix Adafruit_SSD1306");
#endif


//data channel ids
#define maildatachannel "mail"
#define calendardatachannel "cal"
#define timedatachannel "time"


//all notifications have a height of 40
#define iconheight 40

//notification bell icon
#define notwidth 32
static const unsigned char PROGMEM notIcon[] =
{
  0x0, 0x3, 0xc0, 0x0,
  0x0, 0x7, 0xe0, 0x0,
  0x0, 0xf, 0xe0, 0x0,
  0x0, 0xf, 0xf0, 0x0,
  0x0, 0xf, 0xf0, 0x0,
  0x0, 0x3f, 0xfc, 0x0,
  0x0, 0xff, 0xfe, 0x0,
  0x1, 0xff, 0xff, 0x80,
  0x1, 0xff, 0xff, 0x80,
  0x3, 0xff, 0xff, 0xc0,
  0x3, 0xff, 0xff, 0xc0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x7, 0xff, 0xff, 0xe0,
  0x1f, 0xff, 0xff, 0xf0,
  0x7f, 0xff, 0xff, 0xfc,
  0x7f, 0xff, 0xff, 0xfe,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0x7f, 0xff, 0xff, 0xfe,
  0x0, 0x0, 0x0, 0x0,
  0x0, 0x0, 0x0, 0x0,
  0x0, 0xf, 0xf0, 0x0,
  0x0, 0xf, 0xe0, 0x0,
  0x0, 0x7, 0xe0, 0x0,
  0x0, 0x3, 0x80, 0x0
};

//calendar notification icon
#define calwidth 33
static const unsigned char PROGMEM calIcon[] =
{
  0x1, 0x80, 0x0, 0xc0, 0x0,
  0x1, 0x80, 0x0, 0xc0, 0x0,
  0x1, 0x80, 0x0, 0xc0, 0x0,
  0x1, 0x80, 0x0, 0xc0, 0x0,
  0x1, 0x80, 0x0, 0xc0, 0x0,
  0xfd, 0xbf, 0xfe, 0xdf, 0x80,
  0xfd, 0xbf, 0xfe, 0xdf, 0x80,
  0xfd, 0xbf, 0xfe, 0xdf, 0x80,
  0xf9, 0x9f, 0xfc, 0xcf, 0x80,
  0xf9, 0x9f, 0xfc, 0xcf, 0x80,
  0xfc, 0x1f, 0xfc, 0x1f, 0x80,
  0xfc, 0x3f, 0xfe, 0x1f, 0x80,
  0xff, 0xff, 0xff, 0xff, 0x80,
  0xff, 0xff, 0xff, 0xff, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe0, 0x1, 0xce, 0x73, 0x80,
  0xe0, 0x1, 0xce, 0x73, 0x80,
  0xe0, 0x1, 0xce, 0x73, 0x80,
  0xe0, 0x1, 0xce, 0x73, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe7, 0xb9, 0xce, 0x73, 0x80,
  0xe7, 0xbd, 0xce, 0x73, 0x80,
  0xe7, 0xbd, 0xce, 0x73, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe7, 0xbd, 0xce, 0x73, 0x80,
  0xe7, 0xbd, 0xce, 0x73, 0x80,
  0xe7, 0xbd, 0xce, 0x73, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe7, 0xbd, 0xce, 0x3, 0x80,
  0xe7, 0xbd, 0xce, 0x3, 0x80,
  0xe7, 0xb9, 0xce, 0x3, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xe0, 0x0, 0x0, 0x3, 0x80,
  0xff, 0xff, 0xff, 0xff, 0x80,
  0xff, 0xff, 0xff, 0xff, 0x80,
  0xff, 0xff, 0xff, 0xff, 0x80
};

//mail notification icon
#define mailwidth 53
static const unsigned char PROGMEM mailIcon[] =
{
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
  0xff, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf8,
  0xef, 0x80, 0x0, 0x0, 0x0, 0xf, 0xb8,
  0xe7, 0xc0, 0x0, 0x0, 0x0, 0x1f, 0x38,
  0xe3, 0xe0, 0x0, 0x0, 0x0, 0x3e, 0x38,
  0xe1, 0xf8, 0x0, 0x0, 0x0, 0xfc, 0x38,
  0xe0, 0x7c, 0x0, 0x0, 0x1, 0xf0, 0x38,
  0xe0, 0x3e, 0x0, 0x0, 0x3, 0xe0, 0x38,
  0xe0, 0x1f, 0x0, 0x0, 0x7, 0xc0, 0x38,
  0xe0, 0xf, 0xc0, 0x0, 0x1f, 0x80, 0x38,
  0xe0, 0x3, 0xe0, 0x0, 0x3e, 0x0, 0x38,
  0xe0, 0x1, 0xf0, 0x0, 0x7c, 0x0, 0x38,
  0xe0, 0x0, 0xf8, 0x0, 0xf8, 0x0, 0x38,
  0xe0, 0x0, 0x7e, 0x3, 0xf0, 0x0, 0x38,
  0xe0, 0x0, 0x1f, 0x7, 0xc0, 0x0, 0x38,
  0xe0, 0x0, 0xf, 0x8f, 0x80, 0x0, 0x38,
  0xe0, 0x0, 0x7, 0xff, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x3, 0xfe, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0xf8, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x70, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8
};


//variables to handle anything that has to do with time (with DS3231)
unsigned int ssec, mmin, hhrs, ddte, mmth, yyrs; //sec, min, hrs, day, date, month, year
unsigned int psec = 0; //previous sec, used to test if need to update time
byte bsec, bmin, bhrs, bday, bdte, bmth, byrs; //byte variable for retrieving data from DS3231
boolean ttime = false; //recieved "set-time" signal/data from IFTTT? Starting value is false (not in setup)

//variables to handle notifications
String from, subject, title, startat, unid, undetail; //String values for notifications
unsigned int notification = 0; //0: nothing, 1: mail, 2: calendar, 3: unidentified
String fromPython = ""; //whatever data (in string) coming from the serial port from the Linux side
boolean have = false; //have new data coming in? Starting value is false (no data)

//variables to handle transitions and movement in the notifications
unsigned int index = 0; //loading bar status
String subtitle; //notification title substring (no make it fit on the screen)
boolean noLoad = true; //(re)show message because loading bar reset
boolean dismiss = false; //dismiss message


void setup() {
  //initialization of the communication systems
  Serial.begin(9600);
  Serial1.begin(57600);
  display.begin(SSD1306_SWITCHCAPVCC);

  //pinModes for the accelerometer
  pinMode(accX, INPUT);
  pinMode(accY, INPUT);


  //setting up the display for text
  display.clearDisplay();
  display.setRotation(2);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.display();
}

void loop() {
  //read data from serial channel to Linux side, print it out on the Serial port
  fromPython = Serial1.readString();
  Serial.println(fromPython + "<");

  //if there is data interpret it
  if (fromPython != "") {
    Serial.println("Got Something");
    fromPython = fromPython.substring(4); //cut the begining string "MT: ", left with the Message Type
    Serial.println(fromPython);

    //figure out what type of message it is
    if (fromPython == maildatachannel)
      notification = 1;
    else if (fromPython = calendardatachannel)
      notification = 2;
    else if (fromPython = timedatachannel)
      ttime = true;
    else
      notification = 3;

    //if it isn't a time setup:
    if (!ttime) {
      have = true; //have a notification (true)
      Serial.println("sending confirmation");
      confirm(); //let Linux side know that it got the data
      Serial.println("sent and waiting...");
      waitForPython(); //wait for Linux to send the next data point (from address, event title, notification title)
      Serial.println("recieved");
      //send data to variable according to Message Type
      if (notification == 1)
        from = fromPython;
      else if (notification == 2)
        title = fromPython;
      else
        unid = fromPython;
      Serial.println("got Upper, sending confirmation");
      confirm(); //confirm data recieved
      Serial.println("Sent");
      waitForPython(); //wait for Linux to send next data point (subject, event starts at, notification details)
      Serial.println("confirmed");
      //send data to variable according to Message Type
      if (notification == 1)
        subject = fromPython;
      else if (notification == 2)
        startat = fromPython;
      else
        undetail = fromPython;
      Serial.println("Got Lower, done");
      //reset variable
      fromPython = "";
    } else {
      Serial.println("Setting up time"); //<- Setting time
      mmin = fromPython.toInt(); //convert string data to int
      confirm(); //confirm data recieved
      Serial.println("got minute, confirming");
      waitForPython(); //wait for Linux to send hour data point
      hhrs = fromPython.toInt();
      Serial.println("got hour, confirming");
      confirm(); //confirm data recieved
      waitForPython(); //wait for Linux to send date data point
      ddte = fromPython.toInt();
      Serial.println("got date, confirming");
      confirm(); //confirm data recieved
      waitForPython(); //wait for Linux to send month data point
      mmth = fromPython.toInt();
      Serial.println("got month, confirming");
      confirm(); //confirm data recieved
      waitForPython(); //wait for Linux to send year data point
      yyrs = fromPython.toInt();
      Serial.println("got year");

      //clear Serial monitor
      for (int l = 0; l < 50; l++) {
        Serial.println("\n");
      }

      //prompt user to switch to serial monitor
      display.setTextSize(2);
      display.setCursor(0, 0);
      display.println("  Open a\n  Serial\n   Port");
      display.setTextSize(1);
      display.print("To finish time setup");
      display.display();
      while (!Serial) {}// wait for serial monitor/port to open before continueing


      //setting seconds
      Serial.println("Enter currect seconds and send it.");
      Serial.println("The board will automatically add 1 to the number to enter to compensate for any delay");

      String sssec = "";
      do {
        sssec = Serial.readString();
      } while (sssec == "");
      ssec = sssec.toInt() + 1;
      Serial.println("Got time, sending " + ssec);

      //set time to RTC
      settime(ssec, mmin, hhrs, 1, ddte, mmth, yyrs);
      Serial.println("Time has been set: ");

      //read back and show setted time
      readtime(&bsec, &bmin, &bhrs, &bday, &bdte, &bmth, &byrs);
      Serial.println(String(bmth) + "/" + String(bdte) + "/" + String(byrs));
      unsigned int thrs = (unsigned int) bhrs;
      if (thrs >= 12) {
        thrs -= 12;
        Serial.println(String(thrs) + ":" + String(bmin) + ":" + String(bsec) + "PM");
      } else
        Serial.println(String(thrs) + ":" + String(bmin) + ":" + String(bsec) + "AM");
      Serial.println("Serial port can be closed now, time setup complete");
    }
  }
  if (have) {
    //set screen up to display notification
    display.clearDisplay();
    display.setTextSize(2);
    display.setCursor(0, 0);

    //setup subtitle variable
    if (notification == 1)
      subtitle = split(from, '@', 0);
    else if (notification == 2)
      subtitle = title;
    else if (notification == 3)
      subtitle = unid;
    dotdotdot(false); //function to trim a string and add "..." if it is too long

    messageProfile(); //display message's profile: icon and subtitle

    //head tilting loading bar
    while (true) {
      int pulseX = pulseIn(accX, HIGH);
      int angX = ((pulseX / 10) - 500) * 8;
      Serial.println(String(angX));
      if (index == 16)
        break;
      else if (angX > 500) {
        display.drawRect(index * 8, 61, 8, 3, WHITE);
        display.display();
        delay(1);
        index++;
        noLoad = false;
        dismiss = false;
      }
      else if (angX < -500) {
        display.drawRect(128 - (index * 8) - 4, 61, 8, 3, WHITE);
        display.display();
        delay(1);
        index++;
        noLoad = false;
        dismiss = true;
      }
      else {
        if (!noLoad) //reset message profile if cancel load (stop tilting)
          messageProfile();
      }
    }

    if (dismiss)
      dismisser(); //if message dismissal was chosen, run message disimisser
    else
      messageDetail(); //if message detail was chosen, display message details

    //dismissal of message
    index = 0;
    noLoad = true;
    while (true) {
      int pulseX = pulseIn(accX, HIGH);
      int angX = ((pulseX / 10) - 500) * 8;
      Serial.println(String(angX));

      if (index == 16)
        break;
      else if (angX < -500) {
        display.drawRect(128 - (index * 8) - 4, 61, 8, 3, WHITE);
        display.display();
        delay(1);
        index++;
        noLoad = false;
      }
      else {
        if (!noLoad)
          messageDetail();
      }
    }
    dismisser();
    notification = 0;
    have = false;
  } else { //if there is no message display time
    //gather data
    readtime(&bsec, &bmin, &bhrs, &bday, &bdte, &bmth, &byrs);
    ssec = (unsigned int) bsec;
    mmin = (unsigned int) bmin;
    hhrs = (unsigned int) bhrs;
    ddte = (unsigned int) bdte;
    mmth = (unsigned int) bmth;
    yyrs = (unsigned int) byrs;

    if (ssec != psec) { //if there is a difference in time:
      //reset display
      display.clearDisplay();
      display.setCursor(0, 0);
      psec = ssec; //update psec

      //am or pm?
      boolean pm;
      if (hhrs > 12) {
        hhrs -= 12; pm = true;
      }
      else {
        pm = false;
      }
      if (hhrs == 12)
        pm = true;
      else
        pm = false;

      //display date and time
      display.setTextSize(3);
      if (mmin < 10) { //add leading 0 if min is less than 10 ("11:07" rather than "11:7")
        display.print((String) hhrs + ":0" + (String) mmin);
        display.setTextSize(2);
        if (ssec < 10)
          display.println(":0" + (String) ssec);
        else
          display.println(":" + (String) ssec);
      }
      else { //display it normally if don't need to
        display.print((String) hhrs + ":" + (String) mmin);
        display.setTextSize(2);
        if (ssec < 10) //leading 0 thing applies for sec to
          display.println(":0" + (String) ssec);
        else
          display.println(":" + (String) ssec);
      }
      Serial.println((String) hhrs + ":" + (String) mmin);

      //write if it is am or pm based on what was desiced in line 426-437
      display.setCursor(50, 30);
      display.setTextSize(2);
      if (pm)
        display.println("PM");
      else
        display.println("AM");

      //display date at bottom of screen
      display.println(String(mmth) + "/" + String(ddte) + "/" + String(yyrs));
      display.display();
    }
  }
}

void messageDetail() {
  index = 0;
  display.clearDisplay();
  display.setCursor(0, 0);
  display.setTextSize(1);

  if (notification == 1)
    display.println(from);
  else if (notification == 2)
    display.println(title);
  else if (notification == 3)
    display.println(unid);
  display.println("   --------------");

  display.setTextSize(2);
  if (notification == 1)
    display.println(" Subject: ");
  else if (notification == 2)
    display.println("Starts At: ");
  else if (notification == 3)
    display.println(" Details: ");

  dotdotdot(true);
  display.setTextSize(1);
  if (notification == 1)
    display.println(subject);
  else if (notification == 2) {
    display.setTextSize(2);
    display.println(" > " + String(startat));
    display.setTextSize(1);
  }
  else if (notification == 3)
    display.println(undetail);
  display.println("   --------------");

  display.display();
}
void messageProfile() {
  index = 0;
  display.clearDisplay();

  if (notification == 1)
    display.drawBitmap((128 - mailwidth) / 2, 0, mailIcon, mailwidth, iconheight, 1);
  else if (notification == 2)
    display.drawBitmap((128 - calwidth) / 2, 0, calIcon, calwidth, iconheight, 1);
  else if (notification == 3)
    display.drawBitmap((128 - notwidth) / 2, 0, notIcon, notwidth, iconheight, 1);

  display.setCursor(0, 45);
  display.setTextSize(2);
  display.print(subtitle);
  display.display();
}
void dismisser() {
  for (int l = 0; l < 4; l++) {
    display.fillRect(l * 32, 0, 32, 64, WHITE);
    display.display();
    delay(1);
  }
  display.clearDisplay();
  display.fillScreen(WHITE);
  for (int l = 0; l < 4; l++) {
    display.fillRect(l * 32, 0, 32, 64, BLACK);
    display.display();
    delay(1);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.println("\nDismissed!");
  display.display();
  delay(750);
  display.clearDisplay();
  display.display();
  dismiss = false;
}
void settime(byte second, byte minute, byte hour, byte dayOfWeek,
             byte dayOfMonth, byte month, byte year) {
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readtime(byte *second,
              byte *minute,
              byte *hour,
              byte *dayOfWeek,
              byte *dayOfMonth,
              byte *month,
              byte *year) {
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}

void dotdotdot(boolean detail) {
  if (detail) {
    if (notification == 1) {
      if (subject.length() >= 84)
        subject = subject.substring(0, 81) + "...";
    } else if (notification == 3) {
      if (undetail.length() >= 84)
        undetail = undetail.substring(0, 81) + "...";
    }
  } else {
    if (subtitle.length() >= 10)
      subtitle = subtitle.substring(0, 7) + "...";
  }
}
String split(String data, char sep, int index) {
  int found = 0;
  int strIndex[] = {0, -1};
  int maxIndex = data.length() - 1;

  for (int l = 0; l <= maxIndex && found <= index; l++) {
    if (data.charAt(l) == sep || l == maxIndex) {
      found++;
      strIndex[0] = strIndex[1] + 1;
      strIndex[1] = (l == maxIndex) ? l + 1 : l;
    }
  }

  return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void confirm() {
  Serial1.write("1");
}
void waitForPython() {
  while (true) {
    fromPython = Serial1.readString();
    if (fromPython != "")
      break;
  }
}

EUD1_Dev

Python
Python code for this device
"""
EUD1_Dev -Python Code
(v1.0)

Developer: Microbob
Contact: microbob@is88.com
Library credits: kennethreitz (requests), Python (socket, threading, logging), and pySerial
"""
import requests
import socket
import threading
import logging
import serial

#signal to show that the app has started
print 'Started'

# MCS web console data
DEVICE_INFO = {'device_id': 'xxxxxxxx',
               'device_key': 'xxxxxxxxxxxxxxxx'}

# setup logging
logging.basicConfig(level='INFO')

#setup variable to handle heartBeat signals
heartBeatTask = None

#setup variable serial
ss = None

#data channel ids
timedatachannel="time"


#function to setup internal serial connection with Arduino side
def setup():
    global ss
    ss = serial.Serial('/dev/ttyS0', 57600)


#function to create and connec to a channel to recieve data
def establishCommandChannel():
    connectionAPI = \
        'https://api.mediatek.com/mcs/v2/devices/%(device_id)s/connections.csv'
    r = requests.get(connectionAPI % DEVICE_INFO,
                     headers={'deviceKey': DEVICE_INFO['device_key'],
                     'Content-Type': 'text/csv'})
    logging.info('Command Channel IP, port=' + r.text)
    (ip, port) = r.text.split(',')

    # conect to command server
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, int(port)))
    s.settimeout(None)

    # heartbeat to keep channel alive
    def sendHeartBeat(commandChannel):
        keepAliveMessage = '%(device_id)s,%(device_key)s,0' \
            % DEVICE_INFO
        commandChannel.sendall(keepAliveMessage)
        logging.info('beats:%s' % keepAliveMessage)

    def heartBeat(commandChannel):
        sendHeartBeat(commandChannel)

        # restart timer
        global heartBeatTask
        heartBeatTask = threading.Timer(40, heartBeat,
                [commandChannel]).start()

    heartBeat(s)
    return s #channel "id" and data


#wait for serial confirmation from Arduino (confirming that it has recieved the previous sent data point)
def waitForConfirm():
    while True:
        fromBoard = ss.read()
        print fromBoard
        if fromBoard == '1':
            break


#"main" function. When data comes through the commandChannel, it will interpret and run code based on what it got
def waitAndExecuteCommand(commandChannel):
    while True:
        command = commandChannel.recv(1024)
        logging.info('recv:' + command)

        # put in try/except clause because the "command" variable might not have any data
        try:
            #split incomming data to figure out its message type
            messageType = command.split(',')[3] #data channel name will always be the fourth entry (if splitted by ",")
            inData = command.split('%s,' % messageType)[1] #by splitting the data by the messageType+",",
                                                           #you will split the devicekey/id and that data from the content of the data

            #message data clauses will be split by two "#", split the data content by "##" to get the
            #"Upper" data is: email from address, calendar event name, or notification title/name
            #"Lower" data is: email subject, calendar event start time, or notificaiton details
            if messageType!=timedatachannel: #if message type isn't time, then it must be a notification.
                splitted = inData.split('##') #split data to upper and lower

                #set upper and lower variables
                upper = splitted[0]
                lower = splitted[1]
                print 'Upper: %s, Lower: %s' % (upper, lower)

                #send data (over serial) to Arduino
                ss.write('MT: %s' % messageType) #send message type
                print "sent MT"
                waitForConfirm() #wait for Arduino to confirm that it has recieved
                print "confirmed"
                ss.write(upper) #send upper data
                print "sent upper"
                waitForConfirm() #wait for Arduino to confirm that it has recieved
                print "confirmed"
                ss.write(lower) #send lower data
                print "sent lower"
            else: #message type is time, start time setup
                #conversion dict for month
                monthNum={"January":1,"February":2,"March":3,"April":4,"May":5,"June":6,"July":7,"August":8,"September":9,"October":10,"November":11,"December":12}

                #time data comes in a wierd format: MONTH DD, YYYY "at" HH:MMAM/PM, ie March 18, 2017 at 08:47PM
                #utilize python's data manipulation powers to split data and format it to be entered into the DS3231 RTC
                print "splitting time data"
                timeparts=inData.split(' ') #split data by " "
                mmth=monthNum[timeparts[0]] #enter and convert month data (the 1st item in timeparts)
                ddte=timeparts[1][0:2] #cut the 1st two characters in the 2nd item in timeparts (DD, -> DD)
                yyrs=timeparts[2] #get 3rd item in timeparts (YYYY)
                hhrs=timeparts[4][0:2] #cut the 1st two characters in the 4th item in timeparts (HH:MMAM/PM -> HH)
                hrs=int(hhrs) #convert into int, may add 12 if AM/PM is PM
                mmin=timeparts[4][3:5] #cut the 4th and 5th character in the 4th item in timeparts (HH:MMAM/PM -> MM)

                #add 12 if AM/PM is PM
                if timeparts[4][5:]=="PM": #cut the 6th and whatever comes after that (7th) character in the 4th item in timeparts (HH:MMAM/PM -> AM/PM)
                    hrs+=12
                #set hrs to 0 if HH si 24
                if hrs==24:
                    hrs=0
                hhrs=str(hrs) #convert back to string

                print "prompt time data to arduino"
                ss.write('MT: time') #send MT as time to Arduino
                print "wait for confirm"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending minutes"
                ss.write(mmin) #send minutes
                print "sent, waiting for confirmation"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending hours"
                ss.write(hhrs) #send hours
                print "sent, waiting for confirmation"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending date"
                ss.write(ddte) #send date
                print "sent, waiting for confirmation"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending month"
                ss.write(mmth) #send month
                print "sent, waiting for confirmation"
                waitForConfirm() #wait for Arduinot to confirm that it has recieved
                print "confirmed, sending year"
                ss.write(yyrs) #send years
                print "sent, done"
        except Exception: #if there is no data...
            print "haven't recieved yet..."


if __name__ == '__main__': #program loop
    setup() #setup serial connection
    channel = establishCommandChannel() #set channel data
    waitAndExecuteCommand(channel)

Credits

Kenneth Yang

Kenneth Yang

10 projects • 100 followers
Maker, developer, 3D content creator
Thanks to Arduino, Adafruit, kennethreitz, Python, and pySerial.

Comments