NanoRama

Enter Your Project for a chance to win a Nano Grand Prize bundle for the most innovative use of Arduino plus a $400 shopping cart!

Submit an EntrySubmit an Entry  Back to homepage
Project14 Home
Monthly Themes
Monthly Theme Poll

 

PREFACE:

This project was born out of the uncertain times presented by COVID-19.  Across the world, many teams that normally were centralized daily to a work location suddenly found them themselves working remotely.  The first to be displaced to work remotely from their homes were due to child care facilities being closed.  For all, a concern over still being a visible, productive part of the team began to overwhelm their thoughts.  So, this project set out to use an Arduino Nano 33 IoT to keep the team in one another's thoughts, provide a kit project for the kiddies and parents to work together, provide a 6 foot social distancing sensor, and ensure critical business processes stayed in compliance.

 

Pressed for time?  Just view the pictures and read the bold parts!  You'll get it!  Have time to spare?  I'll wear you out with the details.

 

TABLE OF CONTENTS

Desk Ornament:  Sustaining Team Spirit and Business Compliance During These Uncertain Times

 

INTRODUCTION

The end product is a desk ornament to provide four functions:

  • Family Fun:  Provide a kit for employees and their kids to learn about engineering, design, and the Arduino.
  • Remote Team Comradery:  Have a button that when pressed, it will communicate via IoT to all other kits and flash their LEDs.  Employees are to do this anytime they do something awesome to let the remote team know.
  • Social Distancing Stewardship:  Provide a 6 Foot Social Distance sensor on one's desk.  A proximity sensor will flash the LEDs on the module if someone is within 6 feet.
  • Business Compliance:  Alert an employee if critical business compliance metrics are potentially in jeopardy (due to overdue action items, training assignments, etc).

 

The key business rules are be for Health, Safety, and Environmental work processes, Process Safety Management work processes such as Management of Change compliance, and Mechanical Integrity work processes such as turnaround planning.

 

BILL OF MATERIALS

PartDetail

 

Arduino Nano 33 IoT

RGB LEDs (4)RGB LEDs (4)

Momentary SwitchMomentary Switch
OLED DisplayOLED Display
HC-SR04 Proximity SensorHC-SR04 Proximity Sensor
Micro USB Cord
Custom 3D ModelSean Miller's GitHub
Custom Circuit BoardSean Miller's GitHub

 

PRODUCT DESIGN

First, a note on the visual design.  I work for a petroleum refining company.  This project is a home hobby project, but is a present to my team's families - so, in the renderings, I changed my company logos out for the contest.  For my team, the gas pumps make more sense.  The ARC logo is in reference to the web application suite I developed to provide digital workflow and competency development for the various teams.  For this gizmo, it enables the data mining for the IoT using Microsoft Azure based products.

 

Autodesk Fusion 360 Model - Business Compliance Monitor (Left) and Social Distancing Sensor (Right)

 

I drew inspiration from this awesomely restored vintage gas station in McClean, Texas:

Trip Advisor Picture of Restored Gas Station on Route 661

 

 

As my usual M.O., I used Autodesk Fusion 360 to create the product in 3D to ensure everything would fit.  To be sure it is not frustrating to a kid to assemble, I made sure everything would simply push together - no need for glue.  If you haven't ever used Autodesk Fusion 360, you must get it.  It's free and you can design anything including woodworking and buildings.  It's a life changer for a maker and engineer.

 

 

CIRCUIT DESIGN

The circuit is an expansion on the classing Blink circuit.  RGB LEDs are simply 3 LEDs in one bulb.  There is a lead for voltage on each LED and a shared ground.  So, there is a resistor for each voltage lead.  The choice of resistor depends on your specs of LED.  You can use an online calculator2 to limit your amps accordingly per your LED specs.  I'm using 100 Ohm.

Arduino Circuit - Controls LEDs, OLED Display, and the Proximity Sensor

 

Note, there is a voltage divider on the echo pin (Distance-3 pin) coming back from the proximity sensor.  This is because it is echoing 5V's, but the Nano has 3.3V operating logic voltage.  A "voltage divider" is a simple circuit that lets you tap the voltage between two resistors.  I created an Alexa Skill3 that will help you determine the resistors you need, but in this case 3.3K and 1.7K do the trick from 5V to 3.3V.

 

The circuit also communicates to an OLED display on the gas pump using I2C.  This will be used to give specifics if an LED is ever yellow or red signifying a compliance issues - or stating that someone has breached the 6 foot Social Distancing rule.

EAGLE BOARD LAYOUT

 

To ensure it would fit into my ornament, I pushed it from Eagle to Autodesk Fusion 360.  I found that I needed to seek some 3D packages, though, but this served great for an obstruction model:

Autodesk Fusion 360 Push from Eagle made for a good "obstruction" model

 

 

 

I was able to get the board down to $13 for a set of three at OSHPARK.com:

OSHPARK.COM BOARD RENDERING

 

IoT Strategy

The kicker to this project is to have the LEDs change based on a set of business rules.  The easy business rule is to stay 6 feet away from one's desk for social distancing stewardship.  The hard one is having my ARC framework chew up data from all kinds of digital systems to determine when compliance is in the yellow or in the red such as when non-discretionary action items are overdue from incident investigations.  Also, when a button is pressed on the oil reservoir station on the right, we want to flash all other units that the other team members have on their desks.

 

To pull this off, we'll use web sockets - something the Nano will handle nicely.  Each device will simply act as a web client and hit the "mothership" web application with a querystring every minute.

 

For example:  http:///mymothership.com/myapp.aspx?ID=username&Action=GetStatus

 

The mothership app will do some IF...Thens to return back what to do with the LEDs on the calling device.  No need for JSON or anything fancy - just 5 lines of text that state the following:

 

OLED scroll - what to show on the top line of the OLED

LED 1 Color

LED 2 Color

LED 3 Color

Unit Status

 

The "Unit Status" line can override the rest if certain commands are sent such as "celebrate".  This will occur when a user presses the button on the oil reservoir (shown on the right).  The lights will do a pre-canned flash sequence for fun to boost team comradery.

 

TEST SERVER SETUP

As discussed in the IOT Strategy section, our desk ornament will be a web client that hits a web server to get a data packet.  The packet will provide instruction on what it should do with its OLED and LEDs.  So, we need a web server to play around with this.

 

If you have a Windows PC with any operating system since the mid 90's, you already have a web server!  You just need to enable it.

 

To do so, just type "Turn Windows Features On or Off" in the search bar.  Then put a check by Internet Information Services.  Type http://localhost in your browser and you should see the IIS Start page.  Bam! - you now have your own web server!  You can even open a port on your firewall and hit it from anywhere in the world that has internet access.

 

Store the following script as c:\inetpub\wwwroot\default.aspx with this one and you'll have a good mothership IoT server to play with.

 

<%@ Page Title="ARC" Language="VB"%>
<script runat="server">
    Sub Page_Load(Sender As Object, e As EventArgs)
        If Request.QueryString("User") = "sean" Then
            my_response.Text = "Hello, World!" & vbCrLf & "GREEN" & vbCrLf & "YELLOW" & vbCrLf & "BLACK" & vbCrLf 
   if Request.Querystring("Action")="Alert" then my_response.text+="ALERT" else my_response.text+="IDLE"
        Else
            my_response.Text = "I don't know you!" & vbCrLf
        End If
    End Sub
</script>
<asp:label runat="server" ID="my_response" />

CLIENT CODE

Even though we just have 4 LEDs, an OLED display, and a switch, it takes a lot of code to get this one done.  I used an interrupt on pin 13 to catch the button press.  Then some If..thening sends a message to the mother ship server application and lights things up accordingly.

 

// ARC Paperweight Code
// Copyright 2020 by Sean J. Miller, modify use as you wish

#include <Ultrasonic.h>
#include <ss_oled.h>
#include <SPI.h>
#include <WiFiNINA.h>
#include "arduino_secrets.h" //create this file and put it in the same directory as this .ino to store your wifi variables as SECRET_SSID and SECRET_PASS
#define DEBUG false
#define USE_BACKBUFFER
#ifdef USE_BACKBUFFER
static uint8_t ucBackBuffer[1024];
#else
static uint8_t *ucBackBuffer = NULL;
#endif
#define SDA_PIN 18
#define SCL_PIN 19
#define RESET_PIN -1
#define OLED_ADDR 0x3c // Use -1 to have ss_oled auto figure it out.
#define FLIP180 0
#define INVERT 0
#define USE_HW_I2C 0
#define MY_OLED OLED_128x64
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
SSOLED ssoled;
String line_one="";
String line_two="";
String line_three="";
String Scroll="";
String LED1="";
String LED2="";
String LED3="";
String Status="";
boolean changed_display=false; boolean button_pressed=false;
//Ultrasonic
Ultrasonic ultrasonic(20, 21);
double double_distance;
char char_distance[7];
//wifi
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;
IPAddress server(192,168,1,239);  
WiFiClient client;
void setup() {
  if (DEBUG) Serial.begin(9600);
  int rc;
  setupPins();
  setLED(3,"RED");
  
  rc = oledInit(&ssoled, MY_OLED, OLED_ADDR, FLIP180, INVERT, USE_HW_I2C, SDA_PIN, SCL_PIN, RESET_PIN, 400000L); // use standard I2C bus at 400Khz
  if (rc != OLED_NOT_FOUND)
  {
    char *msgs[] = {(char *)"SSD1306 @ 0x3C", (char *)"SSD1306 @ 0x3D",(char *)"SH1106 @ 0x3C",(char *)"SH1106 @ 0x3D"};
    oledFill(&ssoled, 0, 1);
    oledWriteString(&ssoled, 0,0,0,msgs[rc], FONT_NORMAL, 0, 1);
    oledSetBackBuffer(&ssoled, ucBackBuffer);
    delay(2000);
  }
  
  showBootMessage();
  
  if (WiFi.status() == WL_NO_MODULE) {
    if (DEBUG) Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }
  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    if (DEBUG) Serial.println("Please upgrade the firmware");
  }
  setLED(3,"YELLOW");
  showConnectingMessage();
  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    if (DEBUG) Serial.print("Attempting to connect to SSID: ");
    if (DEBUG) Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    
    // wait 10 seconds for connection:
    delay(3000);
  }
  
  setLED(3,"GREEN");
  changed_display=true;showIdleMessage();
  delay(500);
  if (DEBUG) Serial.println("Connected to wifi");
  printWifiStatus();
} /* setup() */
void setupPins()
{
  // HSE 
  pinMode(9,OUTPUT);digitalWrite(9,LOW);
  pinMode(10,OUTPUT);digitalWrite(10,LOW);
  pinMode(11,OUTPUT);digitalWrite(11,LOW);
  //PSM
  pinMode(3,OUTPUT);digitalWrite(9,LOW);
  pinMode(5,OUTPUT);digitalWrite(10,LOW);
  pinMode(6,OUTPUT);digitalWrite(11,LOW);
  //MI
  pinMode(2,OUTPUT);digitalWrite(2,LOW);
  pinMode(A3,OUTPUT);digitalWrite(A3,LOW);
  pinMode(A2,OUTPUT);digitalWrite(A2,LOW);
  //Alert
  pinMode(8,OUTPUT);digitalWrite(8,LOW);
  pinMode(6,OUTPUT);digitalWrite(6,LOW);
  pinMode(3,OUTPUT);digitalWrite(3,LOW);
  //button
  pinMode(13,INPUT_PULLUP); 
  attachInterrupt(digitalPinToInterrupt(13), buttonPressed, LOW);
}
void loop() {
  if (DEBUG) Serial.println("Working");
  
  getMessages();
  setTheLightsPerTheMessage();
  showIdleMessage();
  if(button_pressed) alertTheTeam();
}
void showBootMessage()
{
  cls();
  showOLEDMessage("CONNECTING",1);
  showOLEDMessage("SEARCHING FOR WIFI",2); //line 2 is 20 wide
  showOLEDMessage("STANDBY",3);
  changed_display=true;
}
void showConnectingMessage()
{
  cls();
  showOLEDMessage("CONNECTING",1);
  showOLEDMessage("   GETTING DATA     ",2); //line 2 is 20 wide
  showOLEDMessage("STANDBY",3);
  changed_display=true;
}
void alertTheTeam()
{
  button_pressed=false;
  cls();
  showOLEDMessage("EXCELLENCE!",1);
  showOLEDMessage("        Stand By     ",2); //line 2 is 20 wide
  showOLEDMessage("SENDING ALERT",3);
  changed_display=true;
  sendButtonMessage(); 
  delay(1000);
  showIdleMessage();
}
void buttonPressed()
{
  button_pressed=true;
  changed_display=true;
}
void handleThings(){
  getDistance();
  if (double_distance<6) {
    alertSocialDistancing();
    showPoliceLights();
  }
}
void getMessages(){
  if (DEBUG) Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    if (DEBUG) Serial.println("connected to server");
    // Make a HTTP request:
    client.println("GET /index.aspx?User=sean HTTP/1.1");
    client.println("Host:  192.168.1.239");
    client.println("Connection: close");
    client.println();
  }
  int aborter=0;
  while (!client.available()){
      if (button_pressed) return;  //abort if someone presses the button
      handleThings();
      delay(200);
      if (aborter++ >30) {
        client.stop();
        return;  //just bale if it doesn't respond quickly.
      }
  }
  
  String the_response;
  while (client.available()) {
    char c = client.read();
    if (DEBUG) Serial.write(c);
    the_response+=c;
  }
  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    if (DEBUG) Serial.println();
    if (DEBUG) Serial.println("disconnecting from server.");
    client.stop();
  }
  parseTheResponse(the_response);
  if (Status=="ALERT") {
    changed_display=true;
    cls();
    showOLEDMessage("TEAM AWESOME",1);
    showOLEDMessage("EXCELLENCE REPORTED!",2); //line 2 is 20 wide
    showOLEDMessage("YEAH!",3);
    
    showPoliceLights();
    button_pressed=false;//prevent overpressing
    showPoliceLights();
    button_pressed=false;//prevent overpressing
  }
}
void sendButtonMessage(){
  if (DEBUG) Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    if (DEBUG) Serial.println("connected to server");
    // Make a HTTP request:
    client.println("GET /index.aspx?User=sean&Action=Alert HTTP/1.1");
    client.println("Host:  192.168.1.239");
    client.println("Connection: close");
    client.println();
  }
  int aborter=0;
  while (!client.available()){
      delay(200);
      if (aborter++ >30) {
        client.stop();
        return;  //just bale if it doesn't respond quickly.
      }
  }
  
  String the_response;
  while (client.available()) {
    char c = client.read();
    if (DEBUG) Serial.write(c);
    the_response+=c;
  }
  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    if (DEBUG) Serial.println();
    if (DEBUG) Serial.println("disconnecting from server.");
    client.stop();
  }
  parseTheResponse(the_response);
  if (Status=="ALERT") {
    changed_display=true;
    cls();
    showOLEDMessage("TEAM AWESOME",1);
    showOLEDMessage("EXCELLENCE REPORTED ",2); //line 2 is 20 wide
    showOLEDMessage("YEAH!",3);
    
    showPoliceLights();    
  } else
  {
    changed_display=true;
    cls();
    showOLEDMessage("TEAM AWESOME",1);
    showOLEDMessage("EXCELLENCE REPORTED ",2); //line 2 is 20 wide
    showOLEDMessage("NO RESPONSE!",3);
   
    showPoliceLights();    
  
  }
}
void showPoliceLights()
{
    for (int ii=0;ii<15;ii++) {
      setLED(1,"RED");setLED(2,"RED");setLED(3,"RED");
      delay(100);
      if (button_pressed) break;
      setLED(1,"BLUE");setLED(2,"BLUE");setLED(3,"BLUE");
      delay(100);
    }  
}
void setTheLightsPerTheMessage()
{
  String LED4="";
  if (LED1=="RED") {
    setLED(1,"RED");
    LED4="RED";
  }
  
  if (LED1=="GREEN") {
    setLED(1,"GREEN");
    LED4="GREEN";
  }
  if (LED1=="YELLOW") {
    setLED(1,"YELLOW");
    LED4="YELLOW";
  }   
  if (LED2=="RED") {;
    setLED(2,"RED");
    LED4="RED";
  }  
  if (LED2=="GREEN") {
    setLED(2,"GREEN");
    if (LED4!="RED"&&LED4!="YELLOW")LED4="GREEN";
  }
  if (LED2=="YELLOW") {
    setLED(2,"YELLOW");
    if (LED4!="RED") LED4="YELLOW";
  }
  
  if (LED3=="RED") {;
    setLED(3,"RED");
    LED4="RED";
  }  
  if (LED3=="GREEN") {
    setLED(3,"GREEN");
    if (LED4!="RED"&&LED4!="YELLOW")LED4="GREEN";
  }
  if (LED3=="YELLOW") {
    setLED(3,"YELLOW");
    if (LED4!="RED") LED4="YELLOW";
  }  
  if (LED4=="RED") {;
    setLED(4,"RED");
  }  
  if (LED4=="GREEN") {
    setLED(4,"GREEN");
  }
  if (LED4=="YELLOW") {
    setLED(4,"YELLOW");
  }  
}
void setLED(int LED, String color)
{
  if (LED==1) {
    if (color=="YELLOW") {
      digitalWrite(9,HIGH);
      digitalWrite(10,HIGH);
      digitalWrite(11,LOW);
    }
    else if (color=="GREEN") {
      digitalWrite(9,LOW);
      digitalWrite(10,HIGH);
      digitalWrite(11,LOW);  
    }
    else if (color=="RED")
    {
      digitalWrite(9,HIGH);
      digitalWrite(10,LOW);
      digitalWrite(11,LOW);
    }
    else if (color=="BLUE")
    {
      digitalWrite(9,LOW);
      digitalWrite(10,LOW);
      digitalWrite(11,HIGH);
    }
  } else if (LED==2) {
    if (DEBUG) Serial.println("here +" + color);
    if (color=="YELLOW") {
      digitalWrite(3,HIGH);
      digitalWrite(5,HIGH);
      digitalWrite(6,LOW);     
    }
    else if (color=="GREEN") {
      digitalWrite(3,LOW);
      digitalWrite(5,HIGH);
      digitalWrite(6,LOW);        
    }
    else if (color=="RED")
    {
      digitalWrite(3,HIGH);
      digitalWrite(5,LOW);
      digitalWrite(6,LOW);
    } 
    else if (color=="BLUE")
    {
      digitalWrite(3,LOW);
      digitalWrite(5,LOW);
      digitalWrite(6,HIGH);
    }
  } else if (LED==3) {
      if (DEBUG) Serial.println("here +" + color);
      if (color=="YELLOW") {
        digitalWrite(2,HIGH);
        digitalWrite(A3,HIGH);
        digitalWrite(A2,LOW);     
      }
      else if (color=="GREEN") {
        digitalWrite(2,LOW);
        digitalWrite(A3,HIGH);
        digitalWrite(A2,LOW);        
      }
      else if (color=="RED")
      {
        digitalWrite(2,HIGH);
        digitalWrite(A3,LOW);
        digitalWrite(A2,LOW);
      }
      else if (color=="BLUE")
      {
        digitalWrite(2,LOW);
        digitalWrite(A3,LOW);
        digitalWrite(A2,HIGH);
      }
  }else if (LED==4) {
      if (DEBUG) Serial.println("here +" + color);
      if (color=="YELLOW") {
        digitalWrite(8,HIGH);
        digitalWrite(6,HIGH);
        digitalWrite(3,LOW);     
      }
      else if (color=="GREEN") {
        digitalWrite(8,LOW);
        digitalWrite(6,HIGH);
        digitalWrite(3,LOW);        
      }
      else if (color=="RED")
      {
        digitalWrite(8,HIGH);
        digitalWrite(6,LOW);
        digitalWrite(3,LOW);
      }
      else if (color=="BLUE")
      {
        digitalWrite(8,LOW);
        digitalWrite(6,LOW);
        digitalWrite(3,HIGH);
      }
  }
}
void cls()
{   // clear the screen
    oledFill(&ssoled, 0x0, 1);
}
void showOLEDMessage(char *the_message, int the_line)
{
  switch (the_line)
  {
    case 1: oledWriteString(&ssoled, 0,16,0,the_message, FONT_NORMAL, 0, 1); break;
    case 2: oledWriteString(&ssoled, 0,0,1,the_message, FONT_SMALL, 1, 1); break;
    case 3: oledWriteString(&ssoled, 0,0,3,the_message, FONT_LARGE, 0, 1); break;
  }
}
void showIdleMessage()
{
  if (!changed_display) return;
  changed_display=false;
  cls();
  showOLEDMessage("YOUR STATUS",1);
  showOLEDMessage("",2); //line 2 is 20 wide
  showOLEDMessage("AWESOME!",3);
}
void alertSocialDistancing()
{ 
  cls();
  showOLEDMessage("   ALARM",1);
  showOLEDMessage("  !SOCIAL DISTANCE!  ",2); //line 2 is 20 wide
  showOLEDMessage("BACK UP!",3);
  changed_display=true;
}
void parseTheResponse(String the_response)
{
    // some roughhousing to split this up into our strings.
    the_response=getFromHereToThere(the_response,"<span id=\"my_response\"", "</span>");  // get the lines in between the span.
    
    Scroll=the_response.substring(0,the_response.indexOf('\r')); the_response=the_response.substring(Scroll.length()+2, the_response.length());
    LED1=the_response.substring(0, the_response.indexOf('\r')); the_response=the_response.substring(LED1.length()+2, the_response.length());
    LED2=the_response.substring(0, the_response.indexOf('\r')); the_response=the_response.substring(LED2.length()+2, the_response.length());
    LED3=the_response.substring(0, the_response.indexOf('\r')); the_response=the_response.substring(LED3.length()+2, the_response.length());
    Status=the_response.substring(0, the_response.indexOf('\r'));
    if (DEBUG) Serial.println("hello"+Scroll+LED1+LED2+LED3+Status+"goodbye");
}
String getFromHereToThere(String the_str, String the_start, String the_end)
{
  int ii=0;int start_index=-1;int end_index=-1;
  for (ii=0;ii<(the_str.length()-1);ii++) {
    if (the_str.substring(ii,ii+the_start.length())==the_start)
      start_index=ii;
    else if (the_str.substring(ii,ii+the_end.length())==the_end)
      {end_index=ii; break;}
  }
  if (start_index==-1||end_index==-1) return the_str; else return the_str.substring(start_index+the_start.length()+1,end_index);
}
void getDistance()
{
  double_distance = ((((float)ultrasonic.read())/2.54)/12);  //feet
  if (double_distance<.5) double_distance=8.0;
  memset(char_distance,0,sizeof(char_distance));
  dtoa(double_distance, char_distance, 1);
  String the_string(char_distance);
  the_string+=" ft";
  the_string.toCharArray(char_distance, the_string.length()+1);
  if (DEBUG) Serial.println(the_string);
}
char* dtoa(double dN, char *cMJA, int iP) {
  char *ret = cMJA; long lP=1; byte bW=iP;
  while (bW>0) { lP=lP*10;  bW--;  }
  long lL = long(dN); 
  double dD=(dN-double(lL))* double(lP); 
  if (dN>=0) {
    dD=(dD + 0.5); 
  } else 
    { dD=(dD-0.5); }
  long lR=abs(long(dD));  lL=abs(lL);  
  if (lR==lP) { lL=lL+1;  lR=0;  }
  if ((dN<0) & ((lR+lL)>0)) { *cMJA++ = '-';  } 
  ltoa(lL, cMJA, 10);
  if (iP>0) { while (*cMJA != '\0') { cMJA++; } *cMJA++ = '.'; lP=10; 
  while (iP>1) { 
    if (lR< lP) { *cMJA='0'; cMJA++; } lP=lP*10;  iP--; }
    ltoa(lR, cMJA, 10); 
  }
  return ret; 
}
void printWifiStatus() {
  // print the SSID of the network you're attached to:
  if (!DEBUG) return; 
  
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

BUILD PHOTOS

BEFORE ORDERING MY PCB, I PERFECTED THE CIRCUIT BY BREADBOARDING

 

My first Eagle circuit design was actually way off.  I didn't consider future use of PWM to have dimming effects and I forgot the button.  So, once again, breadboarding saves the day.  I'd been pretty upset after waiting two weeks to get a PCB that requires additional jumpers.

 

TO ELIMINATE THE WICKER LOOK OF 3D PRINTING,

I USE SQUADRON PRODUCTS WHITE PUTTY

 

You can set a 3D printer to print very fine to minimize the wicker look it has from its process.  However, it still never looks perfect.  For ABS plastic, you can use cold acetone vapor polishing4 to smooth out the surface, but its tricky and you can over do it.  For this build, we are using PLA, so we are using putty instead.  I came across Squadron Products putty almost 10 years ago when we built our R2D2.  I used it to fill in cracks on High Impact Polystyrene, before 3D printing was affordable.  It stood the test of time and never became brittle or fell out over the years.  So, I purchased some new for this project.  The formula seems to have changed to make it super fast drying to allow quick handling.

 

MY INDOOR MAKESHIFT PAINTBOOTH

 

My wife and I first painted with acrylic to give an even color base since some parts where printed in silver, some black, and some red.  I then took it to my basement paint booth.  It's a cardboard box with TIG rod hangers that I can spin around from the top allowing to spray all sides.  I point a fan on it after so I can coat every 20 minutes.

 

THE CENSORED PROJECT

Since this is for my work buds, I kept my employer's logos off for this competition and gave a nod to the community, but I'm happy with the results.  I love how Autodesk Fusion 360 will let you visualize every joint and minute detail.  Clicking the button on top, it's really cool how fast the Arduino Nano IoT 33 hits the server and parses the response.  A+ !!

 

PROJECT VIDEO

 

BRIEF DEMO OF THE KEY FEATURES:  IoT Metric Gathering and Social Distance Alarming

With that we end this challenge, but there is still more to come for the design.  I'll slap on my company 3D printed logos, play with LED patterns, and think of inspiring messages to randomly pop up when they least expect it.

 

CRASHING, BURNING, AND RECOVERING

When time permits, I enjoy combing through my blogs trying to make it look pretty on my desktop and iPhone.  I realize that it really shows a different feel than what the project really was like for me.  So, I'm starting a new section in my project blogs  - Crashing, Burning, and Recovering.  The biggest gain from "doing" is learning "what not to do".  Over time, you know so much of what not to do, that you can do new things on the first try.  So, I see it as a definite blog-worthy spin on things.  Here it goes:

 

What HappenedHow I RecoveredWhat I'll Do in the Future.
I tested everything loose.  I then wired it up and glue gunned the wires down and snapped it all together.  The OLED didn't work.I separated the wires and tested a new OLED and it worked.  I swapped popped off the gas pump head and swapped it out.

I'll consider how devastating it would be for the build and if necessary, design for easier access to the screen.

 

Another thing to do, I learned a long time ago, if the part just costs a few bucks, buy a pack of at least 3.

The gas pump has a "neck" that seats the top head.  The neck fit in Autodesk Fusion, but I didn't model the wires for the LEDs which resulted in the neck being an obstruction.I used side cutters to modify the neck to no longer be an obstruction.I'll create obstruction models to represent probable clearances required for wiring.
When I went to test the IoT functionality, I found that my desktop web server wasn't responding.  I had tested another website with it and was no longer pointing to the code of my project.I used the "Recent Files" of notepad++ to locate the code and then changed my webserver.I will create new websites entirely in IIS which simply takes a right click - rather than changing the default directory of the active one.
I suddenly found no time to work on the project due to my day job flowing into night time.I worked extra hours on the weekends for my work until I finally got ahead.Probably the same.  Nothing feels more like a chump than spending 40 hours on a project and not completing it.  I take that back - working on it a day after the competition without realizing the competition was over tops it.  Been there done that.
I thought I'd use a glue gun to set the OLED screen in the back of the pump.  It would dry then boing out.I took 1/4" foam weatherstring and cut it to fit behind the OLED screen to give it positive compressive force to hold it in place.I'd design tiny tabes in Autodesk Fusion that when printed in 3D would click the OLED screen into place.
3D printing Structure and other anomalies to be too tight to fit the oil reservoir pump handle in place.I used a dremmel to drill the hone the hole and then used side cutters on the pump handle to trim it to fit.Do the exact same thing, but not panic next time first.
I printed on a superfine setting overnight to wake up to giant globe of red spaghetti on the end of my 3D printer nozzle and nothing on the print bed.  It clogged the head, so I began to fight everything to get it apart.  Along the way, my 3D printer push fit fitting for the filament feed tube broke off preventing any printing.I had another push fit for plumbing purposes.  I used my mini-lathe to make a metal adapter to receive the threads of the plumbing fitting and adapt to the male machine threads of the 3D printer.I was a little rough with that fitting when it broke.  I should have had a little more patience.  But, I never miss a good opportunity to use the mini lathe, so it was a fun recovery.

 

PROJECT SUMMARY

This was a great project to showcase the Arduino Nano IoT 33.  With so many PWM/Analog/Digital pins available, we needed very few parts.  It's built-in WiFi allowed us to easily connect to our own custom web page.  In turn, we have a great desk ornament gift for the members of my team with some cool smarts built in to help them stay on top of their critical work.  Last, the proximity sensor in the ornament will take what is an awkward moment into a fun moment when office visitors recognize they are too close in terms of social distancing in response to COVID-19.

 

As a side benefit, if you never set up your own web server, I hope you are inspired to do so.  It's just a few clicks and has been for over 20 years! But, so few even know they have that capability.  With it, you can build an IoT "cloud" hub of your very own - free of charge.

 

For more projects and build videos, check out our past blogs covering everything from automotive products to 4D Game Engines.

 

Stay Safe,

-Sean and Connor

REFERENCES

1.  Trip Advisor Photo of Restored Gas Station:  https://www.tripadvisor.co.uk/LocationPhotoDirectLink-g56261-i135165238-McLean_Texas.html

2.  Online LED Resistor Calculator:  https://ledcalculator.net/#p=3.3&v=2&c=20&n=1&o=w

3.  Sean Miller's Voltage Divider Alexa Skill:  https://www.amazon.com/Sean-J-Miller-Voltage-Divider/dp/B07K7L182K

4.  Raising Awesome Cold Acetone Vapor Polishing:  https://www.youtube.com/watch?v=uYixp3_-WRA