Sunday, February 20, 2022

Simpson 260 VOM answers, "Is the internet up?"

-----

It is a pretty commonly uttered question (sometimes loudly) around the home or office; "Is the internet up?"  As the go to IT Support Manager around the house this can get a little tiresome.  Most of the time the internet is up and it's a user or personal device problem that can be solved with a re-boot, re-load, re-etc.  Rarely is the internet really down requiring a router and cable modem reboot or a call to the ISP.  Wouldn't a simple visual check that anyone could quickly understand be helpful? 

-----

I recently found my father's old Simpson 260 meter.  He let me borrow it anytime I wanted with the warning of "DON'T COOK IT!".   My memory recalls only using it for continuity and batteries which is good because I did not have a clue as to what would "cook it".  I decided to put this heirloom to use as an internet monitor.  This project is amazingly useful and simple to duplicate.

-----

The rig uses an ESP8266 to ping different servers.   The ping time (in mS) is displayed on the Simpson 260 and 'percent of full scale'.   In other words a ping of 73mS would be 73% of full scale on the Simpson 260.    We set the source code (see below) to cycle through ten servers and show the ping result every 15 seconds.

-----

If the LAN is down or a ping error is detected the meter "wags" back and forth 5 times and tries another server.   The message to the house is, "If the needle ain't wagging back and forth then your problem ain't with the internet connection!"

-----

Upload the Arduino IDE based source code below to the ESP8266.  Connection to the Simpson 260 is easy. 
 

-----

/*
 *  A vintage Simpson 260 meter to shows network PING times
 *  and if there is a connection to the internet.
 *  
 *  Deflect the Simpson meter from 0-100% of the 2.5V full scall
 *  based on ping times of servers.
 *  
 *  10mS = 10% of full scale.   
 *  45mS = 55% of full scale.
 *  73mS = 73% if full scale.
 *  XXmS = XX% of full scale, etc....
 *  Anything over 100ms is consider terrible and just maxes to 100%
 *  
 *  A bad ping (site not found, network down, etc) will 'wag' the meter
 *  back and forth from 0% to 100% five times then try next ping site.
 *
 *  ESP8266 NodeMCU Board BAUD 115200
 *  HiLetgo 1PC ESP8266 NodeMCU CP2102 ESP-12E Development Board from Amazon
 *  
 *  Full documetation at:
 *  WhiskyTangoHotel.Com    
 *  
 *  FEB2022
 *  
 */

#include <ESP8266WiFi.h>
#include <Pinger.h>

const char* ssid     = "Virus-2.4";      // These vars are your private WIFI
const char* password = "zenakelsocats";  // connection information

// Define some 'ping friendly' sites.   ARRAY starts a 0
String PingSite[] = {  
  "whiskeytangohotel.com",
  "google.com",
  "yahoo.com",
  "bing.com",
  "abc.com",
  "cbs.com",
  "cnn.com",
  "apple.com",
  "pingler.com",
  "mailinator.com"
};  // end ping array define

int Number_of_Ping_Sites = 10;   // counted from the list above
int Secs_Between_Pings = 15;
float Min_Ping_Result = 999;
const int PINGOUT = 2;   // Drives the S260. Blue onboard LED and ~D4
Pinger pinger;

void setup() {
  analogWrite(PINGOUT, 0);
  delay(50);
 
  Serial.begin(115200);
  delay(100);

  // Connect to the WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

// For the ping dot h features https://github.com/bluemurder/esp8266-ping
  pinger.OnEnd([](const PingerResponse& response)
  {
    // Print time information
    if(response.TotalReceivedResponses > 0)
    {
      Serial.printf("Approximate round trip times in milli-seconds:\n");
      Serial.printf(
        "    Minimum = %lums, Maximum = %lums, Average = %.2fms\n",
        response.MinResponseTime,
        response.MaxResponseTime,
        response.AvgResponseTime);
        Min_Ping_Result = response.MinResponseTime;
    }
    
    // Print host data
    Serial.printf("Destination host data:\n");
    Serial.printf(
      "    IP address: %s\n",
      response.DestIPAddress.toString().c_str());
    if(response.DestMacAddress != nullptr)
    {
      Serial.printf(
        "    MAC address: " MACSTR "\n",
        MAC2STR(response.DestMacAddress->addr));
    }
    if(response.DestHostname != "")
    {
      Serial.printf(
        "    DNS name: %s\n",
        response.DestHostname.c_str());
        
        Serial.println("Minimum ping was: " + String(Min_Ping_Result) + "mS." + " Meter to " + String(int(Min_Ping_Result)) + "% of full scale.");
        Serial.println("Delay to next ping is " + String(Secs_Between_Pings) + " seconds...");
        Serial.println("---------------------");
    }
    return true;        
  });  // end ping features

  //Self Test the meter by moving the meter full scale
  // Increase meter value and on board LED brightness
  for(int dutyCycle = 0; dutyCycle < 200; dutyCycle++){   
    // changing the LED brightness with PWM;
    analogWrite(PINGOUT, dutyCycle);
    Serial.println(String(dutyCycle) + " increasing meter self test...");
    //analogWrite(PINGOUT, testval);
    delay(10);
  }   // end meter increase
 
  // Decrease meter value and on board LED brightness
  for(int dutyCycle = 200; dutyCycle > 0; dutyCycle--){
    // changing the LED brightness with PWM
    analogWrite(PINGOUT, dutyCycle);
    Serial.println(String(dutyCycle) + " decreasing meter self test...");
    //analogWrite(PINGOUT, testval);
    delay(10);
  }  // end meter decrease  
  Serial.println("Self test complete!!!");
  Serial.println("---------------------");
 
}   // end void setup

// dutytCycle/2 = ~ the % of 2.5V scale on S260
//    0 dutytCycle =
//   50 dutytCycle = 28%
//  100 dutytCycle = 53%
//  150 dutytCycle = 77%
//  200 dutytCycle = 100%

// Set S260 to +DC.  The + lead to D4.  Neg lead to GND

void loop() {    // loop until the Cowboys win a Super Bowl

  for (int i = 0; i <= (Number_of_Ping_Sites - 1); i++) {  // don't always use the same PingSite; cycle them.
      Serial.println("PingSite[" + String(i) + "]: " + PingSite[i]);
            
      if(pinger.Ping(PingSite[i]) == false)
      {    
         Serial.println("Error during ping command.  Walk the meter 5 times.");
         // Walk the meter back and forth to symbol 'ping error' or network down    
          for (int walk = 0; walk<=4; walk++) {
              // Increase meter value and on board LED brightness
              for(int dutyCycle = 0; dutyCycle < 200; dutyCycle++){   
                // changing the LED brightness with PWM;
                analogWrite(PINGOUT, dutyCycle);
                Serial.println(String(dutyCycle) + " Showing FAIL increasing for: " + PingSite[i]);
                delay(10);
              }   // end fail meter increase
            
              // Decrease meter value and on board LED brightness
              for(int dutyCycle = 200; dutyCycle > 0; dutyCycle--){
                // changing the LED brightness with PWM
                analogWrite(PINGOUT, dutyCycle);
                Serial.println(String(dutyCycle) + " Showing FAIL decreasing for: " + PingSite[i]);
                delay(10);
              }  // end fail meter decrease
          } // end for fail meter back forth walk          
      }  // end if pinger.Ping       

      // Write Ping value to the meter.  Low is better.
      // We basically make percent of full scale equal the ping in mS, ie; 45mS = 45%...
      // Anything over a 100mS is a crappy ping so we make 100mS (100% of scale)
      if (Min_Ping_Result > 100) { Min_Ping_Result = 100; }
      
      analogWrite(PINGOUT, Min_Ping_Result * 2);  // move to meter to display the ping value
      delay(Secs_Between_Pings * 1000);   // delay for next ping    
  }  // end for/next to cycle the PingSites             
}  // end loop until the Cowboys win the Super Bowl
-----