RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

Hello!

This is an on-going write-up of the RiderNet project, version 2. I spent many long months working on the prototype for these units, and have finally finished the build-stage. Now I am preparing to deploy the WiFi routers around the farm and wanted to share the details for comment and feedback.

I have broken the write-up down into multiple responses to this main post, so that those wanting to read the gory details can do so while allowing those how just want to browse the pictures a quick path forward. You can skip the first response if your just browsing through. :)

All feedback and comments are welcome!

Thanks,

Kris

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

This is my formal write-up for RiderNet; an Arduino-managed all-weather WiFi network that I'm building for Misty Brae Farm.

This project would never have happened were it not for Lady Ada and the fantastic tutorials she has created for the many
projects that Adafruit Industries creates and sells. She is an inspiration to the DIY community, for which I am deeply grateful!

Starting Requirements:

I always like to start a project with a set of requirements to work from, otherwise I have been known to get lost in the weeds. ;)

The business need is to carry an IP network out to several barns that have no network connectivity, so that several
Arduino projects can work from within the barns. The second business need was to create a Wifi network for customers
of Misty Brae Farm to use, adding a perk that few other large horse farms will have! The initial plans for the RiderNet
network are projects called RiderScan (WIP) http://forums.adafruit.com/viewtopic.ph ... =RiderScan,
RiderTrack (WIP) and RiderCam (Planned)

* RiderScan uses RFID reader systems to allow riders to badge-in for lessons or work time, to quickly identify
tack with the horse that it belongs to and to allow instructors to see who is riding or who rode on a given day.
* RiderCam is an Arduino-managed set of outdoor wireless video cameras positioned around the farm. Each camera will
sit on small servo platform managed by an Arduino and Adafruit Motor Shield, so the cameras can pan-around.
* RiderTrack is an all-weather Linux server that will sit at the main barn and manage a host of systems, provide
web-sites for RiderScan and video-management software for RiderCam.

These were the requirements I started with in March 2011. I decided on the functional following design:

Structure:

A. I decided to use a mineral-oil cooled/heated system to provide stable temperature control
for the electronics without the need for any air-flow for exposure to the elements.
B. I decided to use a small 15 Watt aquarium heater to heat the mineral oil on cold winter nights.
C. I'm using a Sunterra aquarium pump to circulate the mineral oil around the router.
D. I chose 3/8" inch thick Acrylic for the exterior case, mainly for astetics. Using Acrylic and
bright blue LEDs allows me to add a blue-glow that looks great at night. The Acrylic also
allows me to see what's going on inside. A wooden deck with wood pedistals will provide mounting.
E. Based on the lessons learned from the V1 prototype of RiderNet, the new strategy is to mount
-Nothing- to walls/base of the mineral oil tank itself. Rather the tanks are just like fish
tanks and thus will never leak. My new idea was to mount all the tronics onto a single piece
of Acrylic that is slightly smaller than the dimentions of the tanks. Then the router/tronics
are immersed in the tank without any exterior holes to worry about. Second great advantage of
this method is that it allows me to remove all of the tronics to maintenance/work/replace them
very easily without moving the router tank or dealing with a huge mess. I call them router "slips"
and each is attached to the Top of the tank, meaning I just pull off the top of the tank and
the router/arduino/tronics comes out with it. All of the rubber/weather-stripping is applied
to the inside of the top of the tank, so all waterproofing is done at one point making it much
easier to build. I recommend this to anyone doing mineral oil projects.

Router:

F. I settled on Netgear WNDR-3300 wireless routers because they are inexpensive,
readily available and compatible with the DD-WRT Linux OS.
G. I using DD-WRT for the operating system to run on the wireless routers, because Linux is king
and DD-WRT is an extremely capable WiFi router management system.
H. I decided to build a Wireless Distribution System (WDS) for the wireless network configuration.
This will allow the same Class-C network to span across all routers, so someone can move to
anywhere on the farm and keep the same IP and connectivity.
I. I'm using WPA2 Personal with AES encryption as the security, because I want the bad guys to stay out!

Arduino:

J. I decided on using an Arduino Mega as the controller, because I need the SRAM for my phat code.
The UNO would have enough digital/analog PINs, but I have big plans for the future and want
the expansion room to grow as the project evolves.
K. I decided on using an Ethernet Shield to connect it to the network. This was not my first choice,
I would have MUCH rather used a Wifi network adapter instead of a hard-wire, but the Arduino
Wifi shields were not out yet and the Async Labs shields were gone. :( This still works well,
The Mega connects to the Wifi router it's mounted with using a hard-line cable.
L. I'm using the TMP36 Analog Temperature sensor for measuring the temperature inside the router
enclosure, and an Adafruit 10k precision epoxy thermistor for exterior/outside temperature.
M. I'm using Flex sensor to measure the oil-level inside the routers. The float is a small piece
of styrofoam with a small plastic horse attached, giving it the right weight/float charateristics.
N. I'm using a Photo cell to detect the router power status (sensor sits above the router power LED).
O. I will using a seris of status LED's that will allow me to make a quick determination of a router
status even when mounted high on trees or in the barns.
P. I went with a small web server on each Arduino that reports it's current status, future version
will have the Arduino send heart-beat signals to the RiderTrack server.
Q. I added 7 total LEDs to each setup (5 stand-alone, 2 tri-color RGB) to show power status, temp status,
fluid status, etc (I love blinky LEDs, now is my chance to go wild!).
R. I used the NHK Arduino Mega Protoshield to join the pins for each sensor and LED into groups which I
created/used wire-sets to make the wiring much more net.

Sketch / Code:

The Arduino sketch for managing the routers I call, "RiderNet", and it's purposes are to:

A. Monitor the oil temperature to ensure the router is not too-hot or too-cold. If temperature gets critical,
I use the power-switch tail to disconnect power to the router and equipment (so only the Arduino remains on).
B. Monitor the power-status of the wireless router by watching the power-led with a photo-cell positioned ocer it,
and issue warnings if the router looses power.
C. Monitor the oil-level in the router with a flex sensor, and sound an alarm and shut-down power to the the
router if it looses oil pressure.
D. Provides a small web-server that prints the stats of the router every minute.
E. Provide an SNMP agent so that each router can be polled, and the stats tracked using Zymon/MRTG.
F. Provide a diagnostic capability so that the routers can be tested on/off the bench.

Code: Select all

/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
RaiderNet Showcase version 1.3 - Octoboer 2011
Original Code Examples by Lady Ada of Adafruit Industries
Customization by Kris Kortright of Sojourn Studio
This code released under Creative Commons and is free to all
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#include <SPI.h>
#include <Ethernet.h>
#include <SPI_VFD.h>
#include "DHT.h"


// Uncomment whatever type you're using!
//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)

// resistance at 25 degrees C
#define THERMISTORNOMINAL 10000      
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25   
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR 10000    

// Set IDENTITY; 0=KortrightHaus, 1=Garage, 2=BoardersTack, 3=RiderTrack, 4=FeedRoom, 5=ClubHouse, 6=HutchisonHaus, 7=Backup
//  int IDENTITY = 0;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x40 };
//  byte ip[] = { 192, 168, 1, 180 }; 
//  int IDENTITY = 1;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x41 };
//  byte ip[] = { 192, 168, 1, 181 };
//  int IDENTITY = 2;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x42 };
//  byte ip[] = { 192, 168, 1, 182 };
//  int IDENTITY = 3;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x43 };
//  byte ip[] = { 192, 168, 1, 183 };

int IDENTITY = 4;
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x44 };
byte ip[] = { 192, 168, 1, 184 };

//  int IDENTITY = 5;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x45 };
//  byte ip[] = { 192, 168, 1, 185 };
//  int IDENTITY = 6;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x46 };
//  byte ip[] = { 192, 168, 1, 186 };
//  int IDENTITY = 7;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x47 };
//  byte ip[] = { 192, 168, 1, 187 };
//  int IDENTITY = 8;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x48 };
//  byte ip[] = { 192, 168, 1, 188 };

#define aref_voltage 3.3         // we tie 3.3V to ARef and measure it with a multimeter!

int VERSION = 1.2;
int POWER_INTERRUPT = 1;
int MAX_TEMP_ALARMS = 10;
int MAX_TILT_ALARMS = 10;

int ThermistorOffset = 15;
int TMP36offset = 0;

int samples[NUMSAMPLES];

int AdminState = 0;
int FluidState = 0;
int TempState = 0;
int RouterState = 0;
int RouterPowerState = 0;
int SystemState = 0;
int InternTempF = 0;
int ExternTempF = 0;
int SeriesDelay = (IDENTITY * 60);
int Tilts = 0;
int pinReadDelay = 10;   // ms delay to stabilize reading on Arduino ADC when switching pin-to-pin?
unsigned int Loopy = 0;

int TempAlarms = 0;
int ReverseTiltMode = 0;
int FlexBaseline = 0;
int FlexAlarmLevel = 0;


int DigitalDHTSensor = 2;

int AnalogPhotoCellRouter = 67;
int AnalogInternalTemp = 62;
int AnalogThermistorSensor = 69;
int AnalogFlexSensor = 68;
int AnalogVibrationSensor = 65;

int DigitalRouterPower = 22;

int DigitalArduinoPowerLED = 28;
int DigitalRouterStatusLEDRed = 34;
int DigitalRouterStatusLEDGreen = 32;
int DigitalRouterStatusLEDYellow = 30; 
int DigitalRouterPowerLED = 26;
int DigitalInternalTempLEDred = 48;
int DigitalInternalTempLEDblue = 44;
int DigitalInternalTempLEDgreen = 46;
int DigitalExternalTempLED = 42;       
int DigitalOilLevelLED = 40;
int DigitalVibrationLED = 38;

// Start the VFD.
SPI_VFD vfd(23, 31, 27);

// Start the DHT sensor.
DHT dht(DigitalDHTSensor, DHTTYPE);

// Start the action
Server server(80);
 

void setup()
{
  int i, k;
  int Spinner = 0;
  int SleepTime = 0;
  int FluidStateRaw = 0;
  int FlexTest1 = 0;
  int FlexTest2 = 0;
  int FlexTest3 = 0;
  char buf[128];

  // If you want to set the aref to something other than 5v
  analogReference(EXTERNAL);

  sprintf(buf, "RiderNet Router #%d", IDENTITY);
  // set up the VFD's number of columns and rows:
  vfd.begin(20, 2);
  // Print a message to the VFD.
  vfd.print(buf);

  vfd.setCursor(0, 1);
  vfd.print("Router starting up!");

  pinMode(AnalogPhotoCellRouter, INPUT);
  pinMode(AnalogInternalTemp, INPUT);
  pinMode(AnalogThermistorSensor, INPUT);
  pinMode(AnalogFlexSensor, INPUT);
  pinMode(AnalogVibrationSensor, INPUT);
  pinMode(DigitalDHTSensor, INPUT);

  pinMode(DigitalExternalTempLED, OUTPUT);
  pinMode(DigitalOilLevelLED, OUTPUT);
  pinMode(DigitalVibrationLED, OUTPUT); 
  pinMode(DigitalArduinoPowerLED, OUTPUT); 
  pinMode(DigitalRouterPowerLED, OUTPUT); 
  pinMode(DigitalInternalTempLEDred, OUTPUT); 
  pinMode(DigitalInternalTempLEDgreen, OUTPUT); 
  pinMode(DigitalInternalTempLEDblue, OUTPUT); 
  pinMode(DigitalRouterPower, OUTPUT); 
  pinMode(DigitalRouterStatusLEDYellow, OUTPUT); 
  pinMode(DigitalRouterStatusLEDGreen, OUTPUT); 
  pinMode(DigitalRouterStatusLEDRed, OUTPUT);

  digitalWrite(DigitalArduinoPowerLED, HIGH);

  Serial.begin(9600);

   // start the SPI library:
  SPI.begin();

  dht.begin();

  // Valid Admin States are: 0 = Normal (ON), 1 = Reboot, 2 = Shut-off, 3 = Series Reboot
  AdminState =  0;  
  if(AdminState == 0) {
    digitalWrite(DigitalRouterPower, HIGH);
    digitalWrite(DigitalRouterStatusLEDYellow, LOW);
    digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
    digitalWrite(DigitalRouterStatusLEDRed, LOW);
    SleepTime = 10000;
    digitalWrite(DigitalRouterPower, HIGH);
    for(i = 0; i < SleepTime; i = i + 1000) {
      if(Spinner == 0) {
        digitalWrite(DigitalRouterPowerLED, HIGH);
        Spinner = 1;
      } else {
        digitalWrite(DigitalRouterPowerLED, LOW);
        Spinner = 0;
      }
      delay(1000);
    }

  } else if(AdminState == 1) {
    SleepTime = 30000;
    digitalWrite(DigitalRouterPower, LOW);
    for(i = 0; i < SleepTime; i = i + 1000) {
      if(Spinner == 0) {
        digitalWrite(DigitalRouterPowerLED, HIGH);
        Spinner = 1;
      } else {
        digitalWrite(DigitalRouterPowerLED, LOW);
        Spinner = 0;
      }
      delay(1000);
    }
    digitalWrite(DigitalRouterPower, HIGH);
    digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    digitalWrite(DigitalRouterStatusLEDRed, LOW);
    AdminState = 0;
  } else if(AdminState == 2) {
    if(POWER_INTERRUPT == 1) { 
      digitalWrite(DigitalRouterPower, LOW);
    }
    digitalWrite(DigitalRouterStatusLEDYellow, LOW);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    digitalWrite(DigitalRouterStatusLEDRed, HIGH);
  } else if(AdminState == 3) {
    if(POWER_INTERRUPT == 1) { 
      digitalWrite(DigitalRouterPower, LOW);
    }
    for(i = 0; i < SeriesDelay; i = i + 1000) {
      if(Spinner == 0) {
        digitalWrite(DigitalRouterPowerLED, HIGH);
        Spinner = 1;
      } else {
        digitalWrite(DigitalRouterPowerLED, LOW);
        Spinner = 0;
      }
      delay(100);
    }
    digitalWrite(DigitalRouterPowerLED, HIGH);
    digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    digitalWrite(DigitalRouterStatusLEDRed, LOW);
    delay(SeriesDelay);
    digitalWrite(DigitalRouterPower, HIGH);
    AdminState = 0;
  } else {
    digitalWrite(DigitalRouterPower, HIGH);
  }

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();

  digitalWrite(DigitalRouterStatusLEDRed, HIGH);
  digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
  digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
  digitalWrite(DigitalInternalTempLEDgreen, HIGH);
  digitalWrite(DigitalInternalTempLEDred, HIGH);
  digitalWrite(DigitalInternalTempLEDblue, HIGH);


  // Now set the Flex sensor baseline
  digitalWrite(DigitalOilLevelLED, LOW);

  FlexTest1 = analogRead(AnalogFlexSensor);
  delay(pinReadDelay);
  SleepTime = 1000;
  for(k = 0; k < SleepTime; k = k + 100) {
    if(Spinner == 0) {
      digitalWrite(DigitalOilLevelLED, HIGH);
      Spinner = 1;
    } else {
      digitalWrite(DigitalOilLevelLED, LOW);
      Spinner = 0;
    }
    delay(100);
  }
  sprintf(buf, "Flex Baseline Test #1: %d", FlexTest1);
  Serial.println(buf);

  FlexTest2 = analogRead(AnalogFlexSensor);
  delay(pinReadDelay);
  SleepTime = 1000;
  for(k = 0; k < SleepTime; k = k + 100) {
    if(Spinner == 0) {
      digitalWrite(DigitalOilLevelLED, HIGH);
      Spinner = 1;
    } else {
      digitalWrite(DigitalOilLevelLED, LOW);
      Spinner = 0;
    }
    delay(100);
  }
  sprintf(buf, "Flex Baseline Test #2: %d", FlexTest2);
  Serial.println(buf);

  FlexTest3 = analogRead(AnalogFlexSensor);
  delay(pinReadDelay);
  SleepTime = 1000;
  for(k = 0; k < SleepTime; k = k + 100) {
    if(Spinner == 0) {
      digitalWrite(DigitalOilLevelLED, HIGH);
      Spinner = 1;
    } else {
      digitalWrite(DigitalOilLevelLED, LOW);
      Spinner = 0;
    }
    delay(100);
  }
  sprintf(buf, "Flex Baseline Test #3: %d", FlexTest3);
  Serial.println(buf);
  
  FlexBaseline = ((FlexTest1 + FlexTest2 + FlexTest3) / 3);
  FlexAlarmLevel = (FlexBaseline + 25);
  sprintf(buf, "Flex Baseline set to: %d, Alarm Level set to: %d", FlexBaseline, FlexAlarmLevel);
  Serial.println(buf);


}
 




void ListenForClients(void)
{
  // listen for incoming clients
  Client client = server.available();
  if (client) {
    Serial.println("Got a client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<meta http-equiv=\"refresh\" content=\"30\">");
          
          // print the current readings, in HTML format:
          client.print("" + String());
          client.println("RiderTrack Network Version: \n" + String(VERSION));
          client.println("<br />");
          client.println("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n");
          client.println("<br />");
          if(IDENTITY == 0) {
            client.println("Current Status for Node: mbf-wan-core (Kortrights)");
          } else if (IDENTITY == 1) {
            client.println("Current Status for Node: mbf-wan-edge1 (Garage)");
          } else if (IDENTITY == 2) {
            client.println("Current Status for Node: mbf-wan-edge2 (Boarders Tackroom)");
          } else if (IDENTITY == 3) {
            client.println("Current Status for Node: mbf-wan-barn (Main Barn)");
          } else if (IDENTITY == 4) {
            client.println("Current Status for Node: mbf-wan-edge3 (Feed Room)");
          } else if (IDENTITY == 5) {
            client.println("Current Status for Node: mbf-wan-edge4 (Barn Office)");
          } else if (IDENTITY == 6) {
            client.println("Current Status for Node: mbf-wan-edge5 (Hutchesons)");
          } else if (IDENTITY == 7) {
            client.println("Current Status for Node: mbf-wan-backup (Any Location)");
          } else {
            client.println("Current Status for Node: mbf-wan-backup (Any Location)");
          }
          client.println("<br />");
          client.print("Loop Count: " + String(Loopy));
          client.println("<br />");
          client.print("Series Delay: " + String(SeriesDelay));
          client.println("<br />");
          client.println("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
          client.println("<br />");
          if(AdminState == 0) {
            client.println("Admin Status: OK");
          } else if(AdminState == 1) {
            client.println("Admin Status: Rebooting");
          } else if(AdminState == 2) {
            client.println("Admin Status: Shut-Down");
          } else if(AdminState == 3) {
            client.println("Admin Status: Series-Rebooting");
          } else {
            client.println("Admin Status: Unknown");
          }
          client.println("<br />");
          if(SystemState == 0) {
            client.println("System Status: ON");
          } else if(SystemState == 1) {
            client.println("System Status: OFF");
          }
          client.println("<br />");
          if(RouterState == 0) {
            client.println("Router Status: ON");
          } else if(RouterState == 1) {
            client.println("Router Status: OFF");
          }
          client.println("<br />");
          if(FluidState == 0) {
            client.println("Fluid Status: OK");
          } else if(FluidState == 1) {
            client.println("Fluid Status: ALARM");
          }
          client.println("<br />");
          if(TempState == 0) {
            client.println("Temp Status: Normal");
          } else if(TempState == 1) {
            if(InternTempF < 32) {
              client.println("Temp Status: COLD");
            } else if(InternTempF > 100) {
              client.println("Temp Status: HOT");
            } else {
              client.println("Temp Status: Normal");
            }
          } else if(TempState == 2) {
            if(InternTempF < 0) {
              client.println("Temp Status: FROZEN");
            } else {
              client.println("Temp Status: BOILING");
            }
          }
          client.println("<br />");
          client.print("Air Temperature: " + String(ExternTempF));
          client.println("<br />");
          client.print("Oil Temperature: " + String(InternTempF));
          client.println("<br />");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1000);
    // close the connection:
    client.stop();
  }
}




/* xyzzy */

void loop()
{
  uint8_t i;
  float average;
  float ExternTemp;
  float DHTtemp, DHTtempRaw, DHThumidity;
  float ThermistorTempC, ExternTempF;
  int DHTtempF, InternTempC, InternTemp;
  int SleepTime = 0;
  int Spinner = 0;
  int LightLevelFlag = 0;
  int TiltSensor = 0;
  int TiltSensorRaw = 0;
  int TempCount = 0;
  int SetTempRecovery = 0;
  int x, k, d;
  int AverageTemp;
  int BANNED = 0;
  char buf[128];
  int tf;
  

  SetTempRecovery = 0;
  sprintf(buf, "  ");
  Serial.println(buf);
  Loopy = Loopy + 1;
  sprintf(buf, "Loop: %d", Loopy);
  Serial.println(buf);

  if(AdminState == 2) {
    digitalWrite(DigitalRouterStatusLEDYellow, LOW);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    digitalWrite(DigitalInternalTempLEDblue, LOW);
    digitalWrite(DigitalInternalTempLEDgreen, LOW);
    SleepTime = 2500;
    Spinner = 0;
    for(k = 0; k < SleepTime; k = k + 100) {
      if(Spinner == 0) {
        digitalWrite(DigitalRouterStatusLEDRed, HIGH);
        if(FluidState == 1) {
          analogWrite(DigitalOilLevelLED, 255);
        }
        Spinner = 1;
      } else {
        digitalWrite(DigitalRouterStatusLEDRed, LOW);
        if(FluidState == 1) {
          digitalWrite(DigitalOilLevelLED, 0);
        }
        Spinner = 0;
      }
      delay(100);
    }
  } 

  // =-=-= DHT Temp/Humidity Sensor =-=-=
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  DHThumidity = dht.readHumidity();
  DHTtempRaw = dht.readTemperature();

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(DHTtemp) || isnan(DHThumidity)) {
    Serial.println("Failed to read from DHT");
  } else {
    
    // DHTtemp = (((DHTtempRaw - .5) * 100) * 1.8) + 32;
    DHTtemp = ((1.8 * DHTtempRaw) + 32);
    DHTtempF = int(DHTtemp);

    Serial.print("Humidity: ");
    Serial.print(DHThumidity);
    Serial.print(" %\t");
    Serial.print("Temperature: ");
    Serial.print(DHTtempF);
    Serial.println(" *F");
  }

  // =-=-= Internal Temp Sensor =-=-=
  // =-=-= Thermistor Sensor =-=-=
  // take N samples in a row, with a slight delay
  for (d=0; d< NUMSAMPLES; d++) {
   samples[d] = analogRead(AnalogThermistorSensor);
   delay(pinReadDelay);
  }
 
  // average all the samples out
  average = 0;
  for (d=0; d< NUMSAMPLES; d++) {
     average += samples[d];
  }
  average /= NUMSAMPLES;

  Serial.print("Average thermistor analog reading: "); 
  Serial.println(average);
 
  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  Serial.print("Thermistor resistance: "); 
  Serial.println(average);
 
  float steinhart;
  steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                         // convert to C
  // steinhart -= ThermistorOffset;

/*
  if((steinhart < 20) && (steinhart > 15)) {
    steinhart -= 2;
  } else if((steinhart < 16) && (steinhart > 10)) {
    steinhart -= 4;
  } else if((steinhart < 11) && (steinhart > 5)) {
    steinhart -= 6;
  } else if((steinhart < 6) && (steinhart > 0)) {
    steinhart -= 8;
  } else if((steinhart > 30) && (steinhart < 35)) {
    steinhart += 1;
  } else if((steinhart > 34) && (steinhart < 40)) {
    steinhart += 2;
  } else if((steinhart < 39) && (steinhart > 45)) {
    steinhart += 3;
  } else if((steinhart < 44) && (steinhart > 50)) {
    steinhart += 4;
  }
*/

  float temperatureF = (steinhart * 1.8) + 32.0;
  Serial.print("Thermistor Temperature in C: "); 
  Serial.print(steinhart);
  Serial.println(" *C");
  Serial.print("Thermistor Temperature in F: "); 
  Serial.print(temperatureF);
  Serial.println(" *F");
  InternTempF = int(temperatureF);


  if (InternTempF < -10) {
    digitalWrite(DigitalInternalTempLEDblue, LOW);
    digitalWrite(DigitalInternalTempLEDgreen, HIGH);
    digitalWrite(DigitalInternalTempLEDred, HIGH);
    TempAlarms = TempAlarms + 1;

    if((TempAlarms > MAX_TEMP_ALARMS) && (TempState < 2)) {
      // XYZZY: need to send an alarm to Netcool HERE, Too COLD!! O_O
      sprintf(buf, "Cold Temperature Critical! System freezing up!");
      Serial.println(buf);
      sprintf(buf, "Disconnecting power to router/pump/heater!");
      Serial.println(buf);
      digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      digitalWrite(DigitalRouterStatusLEDRed, LOW);
      digitalWrite(DigitalInternalTempLEDblue, LOW);
      if(POWER_INTERRUPT == 1) {
        digitalWrite(DigitalRouterPower, LOW);
      }
      SystemState = 1;
      AdminState = 2;
      TempState = 2;
    } else {
      sprintf(buf, "Oil Temperature too Cold!");
      Serial.println(buf);
      
      Spinner = 0;
      for(k = 0; k < 1000; k = k + 100) {
        if(Spinner == 0) {
          digitalWrite(DigitalInternalTempLEDblue, HIGH);
          Spinner = 1;
        } else {
          digitalWrite(DigitalInternalTempLEDblue, LOW);
          Spinner = 0;
        }
        delay(100);
      }
      digitalWrite(DigitalInternalTempLEDblue, HIGH);
    }  
  } else if (InternTempF > 140) {
    digitalWrite(DigitalInternalTempLEDblue, HIGH);
    digitalWrite(DigitalInternalTempLEDgreen, HIGH);
    digitalWrite(DigitalInternalTempLEDred, LOW);
    digitalWrite(DigitalExternalTempLED, HIGH);
    TempAlarms = TempAlarms + 1;
    
    if((TempAlarms > MAX_TEMP_ALARMS) && (TempState < 2)) {
      // XYZZY: need to send an alarm to Netcool HERE, Too HOT!! O_O
      sprintf(buf, "Hot Temperature Critical! System is burning up!");
      Serial.println(buf);
      digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      digitalWrite(DigitalRouterStatusLEDRed, LOW);
      digitalWrite(DigitalInternalTempLEDred, LOW);
      if(POWER_INTERRUPT == 1) {
        digitalWrite(DigitalRouterPower, LOW);
      }
      SystemState = 1;
      AdminState = 2;
      TempState = 2;
    } else {
      sprintf(buf, "Oil Temperature too Hot!");
      Serial.println(buf);
      
      Spinner = 0;
      for(k = 0; k < 1000; k = k + 100) {
        if(Spinner == 0) {
          digitalWrite(DigitalRouterStatusLEDRed, HIGH);
          Spinner = 1;
        } else {
          digitalWrite(DigitalRouterStatusLEDRed, LOW);
          Spinner = 0;
        }
        delay(100);
      }
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    }  
  } else if(InternTempF < 40) {
    if(TempState == 2) {
      if(AdminState == 2) {
        if(SystemState == 1) {
          SetTempRecovery = 1;
        }
      }
    }
    digitalWrite(DigitalInternalTempLEDblue, LOW);
    digitalWrite(DigitalInternalTempLEDgreen, HIGH);
    digitalWrite(DigitalInternalTempLEDred, HIGH);
    digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
    TempState = 1;
    sprintf(buf, "Its too damn Cold in here! Temp < 40!");
    Serial.println(buf);
  } else if (InternTempF > 100.0) {
    if(TempState == 2) {
      if(AdminState == 2) {
        if(SystemState == 1) {
          SetTempRecovery = 1;
        }
      }
    }
    digitalWrite(DigitalInternalTempLEDblue, HIGH);
    digitalWrite(DigitalInternalTempLEDgreen, HIGH);
    digitalWrite(DigitalInternalTempLEDred, LOW);
    digitalWrite(DigitalRouterStatusLEDYellow, LOW);
    TempState = 1;
    sprintf(buf, "Its too BANNED Hot in here man! Temp > 100!");
    Serial.println(buf);
  } else {
    if(TempState == 2) {
      if(AdminState == 2) {
        if(SystemState == 1) {
          SetTempRecovery = 1;
        }
      }
    }
    if(TempState == 1) {
      sprintf(buf, "Exterior tempeature returned to normal range (%d)", ExternTempF);
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalInternalTempLEDblue, HIGH);
      digitalWrite(DigitalInternalTempLEDgreen, LOW);
      digitalWrite(DigitalInternalTempLEDred, HIGH);
      TempState = 0;
    }
  }
  if(SetTempRecovery == 1) {
    sprintf(buf, "Internal Oil tempeature returned to normal range!");
    Serial.println(buf);
    sprintf(buf, "Starting router/pump/heater power!");
    Serial.println(buf);
      
    TempState = 0;
    TempAlarms = 0;
    AdminState = 0;
    if(SystemState == 1) { 
      sprintf(buf, "Tempeature returned to normal range, re-activating power!", TiltSensorRaw);
      Serial.println(buf);
      digitalWrite(DigitalRouterPower, HIGH);
      SystemState = 0;
    }
    SetTempRecovery = 0;
    digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    if(RouterState == 0) {
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    }
  }





  // =-=-= Light (power) Sensor =-=-=
  int LightLevel = analogRead(AnalogPhotoCellRouter);
  delay(pinReadDelay);
  LightLevel = map(LightLevel, 0, 900, 0, 10); 
  LightLevel = constrain(LightLevel, 0, 10);
  if(LightLevel > 4) {
    if(RouterState == 0) {
      if(RouterPowerState == 0) {
        digitalWrite(DigitalRouterPowerLED, HIGH);
      }
      RouterPowerState = 1;
      sprintf(buf, "Router power is ON (sensor: %d)", LightLevel);
      Serial.println(buf);
    } else {
      digitalWrite(DigitalRouterPowerLED, HIGH);
      RouterPowerState = 1;
      sprintf(buf, "Router power is ON, it must have recovered! (sensor: %d)", LightLevel);
      Serial.println(buf);
      // XYZZY: Send an Recovery alarm to Netcool HERE.
      RouterState = 0;
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalRouterStatusLEDGreen, LOW);
      digitalWrite(DigitalRouterStatusLEDRed, LOW);
    }
  } else {
    if(AdminState == 0) {
      digitalWrite(DigitalRouterPowerLED, LOW);
      sprintf(buf, "Router power is OFF and should be ON!(sensor: %d)", LightLevel);
      Serial.println(buf);
      // XYZZY: Send an alarm to Netcool HERE.
      RouterState = 1;
      RouterPowerState = 0;
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalRouterStatusLEDGreen, LOW);
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    } else {
      digitalWrite(DigitalRouterPowerLED, LOW);
      sprintf(buf, "Router power is OFF (sensor: %d)", LightLevel);
      Serial.println(buf);
    }
  }

  // =-=-= Tilt Sensor =-=-=
  TiltSensorRaw = analogRead(AnalogFlexSensor);
  delay(pinReadDelay);
  sprintf(buf, "Raw Flex Resistance: %d, Alarm Level is: %d, Delta = %d", TiltSensorRaw, FlexAlarmLevel, (FlexAlarmLevel - TiltSensorRaw));
  Serial.println(buf);

  if((TiltSensorRaw > FlexAlarmLevel) || (ReverseTiltMode == 1)) {
    TiltSensor = 1;
  } else {
    TiltSensor = 0;
  }
  if(TiltSensor == 0) {
    analogWrite(DigitalOilLevelLED, 0);
    Tilts = 0;

    if(FluidState == 1) {
      sprintf(buf, "Fluid Level Test: PASS! (raw: %d)", TiltSensorRaw);
      Serial.println(buf);
      FluidState = 0;
      if(AdminState == 2) {
        AdminState = 0;
        if(SystemState == 1) { 
          // XYZZY - Send tilt Recovery trap to Netcool.
          sprintf(buf, "Fluid levels Restored!, re-activating Power!", TiltSensorRaw);
          Serial.println(buf);
          digitalWrite(DigitalRouterPower, HIGH);
          SystemState = 0;
        } else {
        // XYZZY - Send tilt Recovery trap to Netcool.
        }
      } else {
        // XYZZY - Send tilt Recovery trap to Netcool.
      }
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      if(RouterState == 0) {
        digitalWrite(DigitalRouterStatusLEDRed, LOW);
      }
    } else {
      // XYZZY - Send tilt Recovery trap to Netcool.
      sprintf(buf, "Fluid Level Test: PASS");
      Serial.println(buf);
      Tilts = 0;
    }
  } else {
    analogWrite(DigitalOilLevelLED, 255);
    Tilts = Tilts + 1;

    if(Tilts >= MAX_TILT_ALARMS) {
      // XYZZY: need to send an alarm to Netcool HERE, were out of fluid!! O_O
      sprintf(buf, "Fluid Level Alarm!! Router is out of Oil!");
      Serial.println(buf);
      sprintf(buf, "Disconnecting power to router, pump and heater!");
      Serial.println(buf);
      analogWrite(DigitalOilLevelLED, 255);
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalRouterStatusLEDGreen, LOW);
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
      Spinner = 0;
      for(k = 0; k < 1000; k = k + 100) {
        if(Spinner == 0) {
          analogWrite(DigitalOilLevelLED, 255);
          Spinner = 1;
        } else {
          analogWrite(DigitalOilLevelLED, 0);
          Spinner = 0;
        }
        delay(100);
      }
      analogWrite(DigitalOilLevelLED, 255);
      if(POWER_INTERRUPT == 1) {
        digitalWrite(DigitalRouterPower, LOW);
      }
      SystemState = 1;
      AdminState = 2;
      FluidState = 1;
    } else if((Tilts > 4) && (Tilts < MAX_TILT_ALARMS)) {
      // XYZZY: need to send an alarm to Netcool HERE, were out of fluid!! O_O
      sprintf(buf, "Fluid Level Alarm! (Tilts: %d)", Tilts);
      Serial.println(buf);
      
      analogWrite(DigitalOilLevelLED, 255);
    } else {
      // XYZZY: need to send an alarm to Netcool HERE, were out of fluid!! O_O
      sprintf(buf, "Fluid Sensor has moved! (Tilts: %d), Raw: %d", Tilts, TiltSensorRaw);
      Serial.println(buf);
      
      Spinner = 0;
      for(k = 0; k < 1000; k = k + 100) {
        if(Spinner == 0) {
          analogWrite(DigitalOilLevelLED, 255);
          Spinner = 1;
        } else {
          analogWrite(DigitalOilLevelLED, 0);
          Spinner = 0;
        }
        delay(100);
      }
      analogWrite(DigitalOilLevelLED, 0);
    }
  }
 



  // =-=-= Vibration Sensor =-=-=
/*
  BANNED = analogRead(AnalogVibrationSensor);
  delay(pinReadDelay);
  Serial.print("Raw Vibration Sensor Reading: "); 
  Serial.print(BANNED);
  Serial.println(".");
*/

  vfd.clear();

  int temp = int(DHTtempF);
  int humidity = int(DHThumidity);
  sprintf(buf, "Temp: %dF  Hum: %d%%", temp, humidity);
  vfd.setCursor(0, 0);
  vfd.print(buf);

  if(AdminState == 2) {
    sprintf(buf, "Emergency Shutdown!");
  } else if(FluidState == 1) {
    sprintf(buf, "Oil Level Low/Out!");
  } else if(TempState == 1) {
    if(InternTempF > 0) {
      sprintf(buf, "Alarm: Oil Temp High");
    } else {
      sprintf(buf, "Alarm: Oil Temp Low");
    }
  } else if(TempState == 2) {
    if(InternTempF > 0) {
      sprintf(buf, "PANIC! Oil Temp High");
    } else {
      sprintf(buf, "PANIC! Oil Temp Low");
    }
  } else if(RouterState == 1) {
    sprintf(buf, "Router Power Off?!");
  } else {
    sprintf(buf, "All is Good at MBF!");
  }
  vfd.setCursor(0, 1);
  vfd.print(buf);


  // Now determine final LED state
  if(AdminState == 0) {
    if(RouterState == 0) {
      digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
      digitalWrite(DigitalRouterStatusLEDGreen, LOW);
      delay(100);
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      digitalWrite(DigitalArduinoPowerLED, HIGH);
      delay(100);
      digitalWrite(DigitalArduinoPowerLED, LOW);
      digitalWrite(DigitalRouterPowerLED, HIGH);
      delay(100);
      digitalWrite(DigitalRouterPowerLED, LOW);
      digitalWrite(DigitalInternalTempLEDgreen, LOW);
      digitalWrite(DigitalInternalTempLEDred, LOW);
      delay(100);
      digitalWrite(DigitalInternalTempLEDgreen, HIGH);
      digitalWrite(DigitalInternalTempLEDred, HIGH);
      digitalWrite(DigitalExternalTempLED, HIGH);
      delay(100);
      digitalWrite(DigitalExternalTempLED, LOW);
      delay(100);
      digitalWrite(DigitalOilLevelLED, HIGH);
      delay(100);
      digitalWrite(DigitalOilLevelLED, LOW);
      delay(100);
      digitalWrite(DigitalVibrationLED, HIGH);
      delay(100);
      digitalWrite(DigitalVibrationLED, LOW);
      delay(100);

    } else {
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      digitalWrite(DigitalRouterStatusLEDRed, LOW);
      digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
      SleepTime = 1000;
      for(k = 0; k < SleepTime; k = k + 100) {
        if(Spinner == 0) {
          digitalWrite(DigitalRouterPowerLED, HIGH);
          digitalWrite(DigitalRouterStatusLEDRed, HIGH);
          Spinner = 1;
        } else {
          digitalWrite(DigitalRouterPowerLED, LOW);
          digitalWrite(DigitalRouterStatusLEDRed, LOW);
          Spinner = 0; 
        }
        delay(100);
      }
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    }
  }

  sprintf(buf, "SystemState: %d, AdminState: %d, FluidState: %d, TempState: %d", SystemState, AdminState, FluidState, TempState);
  Serial.println(buf);
  for(d=0;d<=100;d++) {
    ListenForClients();
    delay(10);
  }
}


float getVoltage(int pin) {
  return (analogRead(pin) * .004882814); 
}
This concludes the gory details. :) If there is anything I've left off that your interested in, don't hesitate to ask!

Kris

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

Screenshot Threads:

Attached below are a few screenshots of the router when it was completed and ready for oil testing.
I learned alot of valuable lessons about working with mineral oil, acryllic, dd-wrt and most especially
Arduino! I'll post more screenshots and information as the project develops. I whipped-up a layout in
Fritzing (such a cool name) to show the layout, though I can't get Fritzing to make the PCD or diagram
right. Still this will show electronically what I'm trying to do for the wifi routers:
Wiring Diagram from Fritzing
Wiring Diagram from Fritzing
Fritz_RiderNet_WireDiagram2.jpg (140.6 KiB) Viewed 12879 times
Here's a close-up of my oil-level detector, which uses a Ribbon Sensor from Adafruit attached to a small
diving board near the top. The styrofoam and horse-float are light-enough to float on top of mineral oil,
but heavy-enough to fall as the oil level drops, thus bending the sensor:
The custom oil-level sensors I created from a Flex sensor attached to a styrofoam and Horse float!
The custom oil-level sensors I created from a Flex sensor attached to a styrofoam and Horse float!
RiderNet_RibbonFloatSensors.JPG (844.38 KiB) Viewed 12879 times
This is a quick pic of the remaining components - a 10k epoxy thermistor for exterior temperature
detection, a TMP36 analog temperature sensor to measure the oil temperature inside the router and
a photocell to measure the light coming off the power LED of the wireless router:
The completed NHK Arduino Mega Protoshields, LED front panels and sensors (bagged) - ready for installation.
The completed NHK Arduino Mega Protoshields, LED front panels and sensors (bagged) - ready for installation.
RiderNetV2_Components.jpg (316.86 KiB) Viewed 12879 times

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

I designed the front-panel to make it a little cleaner and remove the sensor mounts so it just handles LEDs.
I then used the Mega Protoshields from Adafruit (http://www.adafruit.com/products/192) combined with the
Shield stacking headers for Arduino (http://www.adafruit.com/products/85) to create a Mega shield that would
also support the Ethernet shield on-top:
The Arduino components stacked together, ready for deployment
The Arduino components stacked together, ready for deployment
RiderNet3_Stacked.JPG (195.02 KiB) Viewed 12875 times
The main function of the shield is to provide 5 pairs of sensor pins that lead to the mounted sensors in/around
the router/casing and to clean-up the wiring connections between the Arduino and the front LED Panel. I have to
say I really like the Mega proto shield, though I would recommend to Adafruit to add a sentense on the Mega
Shield page that mentions it doesn't come with the shield stacking headers, and provide a link to the shield
stacking headers for users that need to stack stuff on top. That Adafruit sells both makes it really convenient:
The custom NHK Mega Protoshield I created to join the pins into bundles for cabling
The custom NHK Mega Protoshield I created to join the pins into bundles for cabling
RiderNet3_MegaShield.JPG (348.25 KiB) Viewed 12875 times

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

Here are some pictures of the completed "Slips" of electronics, the single sheets of acrylic to which all of the components are attached. This allows me to Not drill holes in the sides of the mineral oil tanks, ensuring they will remain water tight. It also makes for easy maintenance, as I can just pull the entire slip out of the oil tank when I need to work on it, and slip it back in when I'm done. :)

First a picture of the router slips from the front:
Frontal shot of an electronics &quot;slip&quot;
Frontal shot of an electronics "slip"
RouterSlipOverPic.JPG (334.02 KiB) Viewed 12875 times
A picture of the attachments from behind:
Rear shot of an electronics slip:
Rear shot of an electronics slip:
RouterSlipUnderPic.JPG (335 KiB) Viewed 12875 times
A shot of the completed slips, ready for installation:
Screenshot of the completed units, ready to go!
Screenshot of the completed units, ready to go!
RouterSlipsOnTable.JPG (283.01 KiB) Viewed 12875 times

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

After completion I took these screenshots, and dressed one of them up with a breakdown of the RiderNet components. This
unit is the "Showcase Model", as I mounted a VFD LCD and one of the new Adafruit temp/humidity sensors outside the router
for exterior measurements. This one will go in the main barn, so it wont be directly exposed to rain/snow - so I figured
it would be nice to have the temp/humidity of the barn displayed on the VFD. The VFD LCD working with the "showcase"
router looks very nice - especially at night. :) The breakdown screenshot is below:
Description Shot
Description Shot
RiderNetV2_Closeup_Description.jpg (642.32 KiB) Viewed 12870 times
Here is a screenshot of all 6 routers side-by-side on the bench in full lighting:
Frontal screenshot in full lighting
Frontal screenshot in full lighting
RiderNetV2_InDaylight_SmallSize.jpg (416.93 KiB) Viewed 12870 times
And here's a shot with all the lights out: ;)
Frontal screenshot at night ;)
Frontal screenshot at night ;)
RiderNetV2_AtNight_SmallSize.jpg (319.22 KiB) Viewed 12870 times
I also made a small video of the system on YouTube:

http://www.youtube.com/watch?v=Asc_1S4uJys

I did some outdoor placement / range testing yesterday and discovered (to my great joy) that the WiFi routers can make the distances I have set-out around the farm. A few of the hauls are long, but the browsing speed is still very good.

That completes my initial write-up of RiderNet. :) I very much welcome feedback and input on how I could make the system better. I will continue posting smaller updates as the deployment progresses this week around the farm. Thanks for reading!

Cheers,

Kris

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

Update - RiderNet is now Deployed!! :)

(Well, at least half of it anyway!) This day has been 9 months in the making, I'm so glad it's finally done. :shock:

I'll deploy the other three next weekend, as I have to run power-leads to those locations. The key routers that connect from my house <-> backyard tree <-> farm clubhouse <-> main barn - is complete aside from waterproofing the power cord connection (later today). The other 3 will be deployed to the main riding arenas, but those aren't necessary to get the server up and running.

I built 5 custom wooden frames made of pressure treated lumber to hold the routers out around the farm. I designed them to maximize the amount of protection for the routers while minimizing the amount of wood used (so we can still see all the tronics inside!). Most importantly, the frames do not obscure or cover Any of the WIFI router antenna's, so the frames won't reduce radio reception at all. The result was a double ring of 1" boards, connected by risers of the same wood and secured to a single 13" piece of 2" x 6" lumber as the base:
RiderNet router frames
RiderNet router frames
RouterFrames_Small.jpg (342.47 KiB) Viewed 12488 times
I took screenshots of all 3 deployed routers in the daytime, shown below. I'll take another round of pictures later today with more horses around and some at night - cause that's when they really show off. Here are pics of the Main Barn router, which give a good view of how the frames hold the routers:
Main Barn router from front
Main Barn router from front
Mainbarn_Front_Small.jpg (364.36 KiB) Viewed 12488 times
And another shot of the same router from the side, showing more of the main barn during morning chores!
Main Barn router from the side
Main Barn router from the side
Mainbarn_Side_Small.JPG (280.16 KiB) Viewed 12488 times
Next post will have three more screenshots. :) All feedback welcome!!

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

The next three screenshots are of the router in the tree in my backyard in daytime. Note that I attached two vertical rails to the back of this router's frame, so that I could use nylon rope to tie/attach the frame to the tree WITHOUT HARMING THE TREE. :) I love nature, no reason to burden the tree with nails and screws - I attached it at enough points that it isn't moving. It's very hard to see in this picture, I'll get a better shot this evening when the sun isn't glaring me out.
RiderNet router in a tree
RiderNet router in a tree
TreeHouse_Front_Small.JPG (403.3 KiB) Viewed 12485 times
The next screenshot shows the router attached to the clubhouse deck (above the small barn) in the daytime:
Small barn / club house router from the front
Small barn / club house router from the front
Clubhouse_Front_Small.jpg (394.57 KiB) Viewed 12485 times
The last screenshot shows the same clubhouse router from behind, overlooking the paddocks and main field (nice morning shot). Usually more horses there in the background, but I had just let them all out and they tend to run around towards the further areas first thing in the morning. :) More shots from this angle later when more horses are grazing:
Small barn / club house RiderNet router from the back
Small barn / club house RiderNet router from the back
Clubhouse_Back_Small.jpg (373.95 KiB) Viewed 12485 times
All feedback and comments are most welcome! :) I'll post another round of 3 tonight in the dark.

Kris

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

Doh!

I almost forgot the important bits - the Arduino Sketch that drives everything (I included the showcase version that has the VFD and DHT sensor included):

Code: Select all

/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
RaiderNet Showcase version 1.3 - Octoboer 2011
Original Code Examples by Lady Ada of Adafruit Industries
Customization by Kris Kortright of Sojourn Studio
This code released under Creative Commons and is free to all
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#include <SPI.h>
#include <Ethernet.h>
#include <SPI_VFD.h>
#include "DHT.h"


// Uncomment whatever type you're using!
//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)

// resistance at 25 degrees C
#define THERMISTORNOMINAL 10000      
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25   
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR 10000    

// Set IDENTITY; 0=KortrightHaus, 1=Garage, 2=BoardersTack, 3=RiderTrack, 4=FeedRoom, 5=ClubHouse, 6=HutchisonHaus, 7=Backup
//  int IDENTITY = 0;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x40 };
//  byte ip[] = { 192, 168, 1, 180 }; 
//  int IDENTITY = 1;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x41 };
//  byte ip[] = { 192, 168, 1, 181 };
//  int IDENTITY = 2;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x42 };
//  byte ip[] = { 192, 168, 1, 182 };
//  int IDENTITY = 3;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x43 };
//  byte ip[] = { 192, 168, 1, 183 };

int IDENTITY = 4;
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x44 };
byte ip[] = { 192, 168, 1, 184 };

//  int IDENTITY = 5;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x45 };
//  byte ip[] = { 192, 168, 1, 185 };
//  int IDENTITY = 6;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x46 };
//  byte ip[] = { 192, 168, 1, 186 };
//  int IDENTITY = 7;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x47 };
//  byte ip[] = { 192, 168, 1, 187 };
//  int IDENTITY = 8;
//  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x3F, 0x48 };
//  byte ip[] = { 192, 168, 1, 188 };

#define aref_voltage 3.3         // we tie 3.3V to ARef and measure it with a multimeter!

int VERSION = 1.2;
int POWER_INTERRUPT = 1;
int MAX_TEMP_ALARMS = 10;
int MAX_TILT_ALARMS = 10;

int ThermistorOffset = 15;
int TMP36offset = 0;

int samples[NUMSAMPLES];

int AdminState = 0;
int FluidState = 0;
int TempState = 0;
int RouterState = 0;
int RouterPowerState = 0;
int SystemState = 0;
int InternTempF = 0;
int ExternTempF = 0;
int SeriesDelay = (IDENTITY * 60);
int Tilts = 0;
int pinReadDelay = 10;   // ms delay to stabilize reading on Arduino ADC when switching pin-to-pin?
unsigned int Loopy = 0;

int TempAlarms = 0;
int ReverseTiltMode = 0;
int FlexBaseline = 0;
int FlexAlarmLevel = 0;


int DigitalDHTSensor = 2;

int AnalogPhotoCellRouter = 67;
int AnalogInternalTemp = 62;
int AnalogThermistorSensor = 69;
int AnalogFlexSensor = 68;
int AnalogVibrationSensor = 65;
int AnalogBlueFloods = 54;
int DigitalRouterPower = 22;

int DigitalArduinoPowerLED = 28;
int DigitalRouterStatusLEDRed = 34;
int DigitalRouterStatusLEDGreen = 32;
int DigitalRouterStatusLEDYellow = 30; 
int DigitalRouterPowerLED = 26;
int DigitalInternalTempLEDred = 48;
int DigitalInternalTempLEDblue = 44;
int DigitalInternalTempLEDgreen = 46;
int DigitalExternalTempLED = 42;       
int DigitalOilLevelLED = 40;
int DigitalVibrationLED = 38;

// Start the VFD.
SPI_VFD vfd(23, 31, 27);

// Start the DHT sensor.
DHT dht(DigitalDHTSensor, DHTTYPE);

// Start the action
Server server(80);
 

void setup()
{
  int i, k;
  int Spinner = 0;
  int SleepTime = 0;
  int FluidStateRaw = 0;
  int FlexTest1 = 0;
  int FlexTest2 = 0;
  int FlexTest3 = 0;
  char buf[128];

  // If you want to set the aref to something other than 5v
  analogReference(EXTERNAL);

  sprintf(buf, "RiderNet Router #%d", IDENTITY);
  // set up the VFD's number of columns and rows:
  vfd.begin(20, 2);
  // Print a message to the VFD.
  vfd.print(buf);

  vfd.setCursor(0, 1);
  vfd.print("Router starting up!");

  pinMode(AnalogPhotoCellRouter, INPUT);
  pinMode(AnalogInternalTemp, INPUT);
  pinMode(AnalogThermistorSensor, INPUT);
  pinMode(AnalogFlexSensor, INPUT);
  pinMode(AnalogVibrationSensor, INPUT);
  pinMode(DigitalDHTSensor, INPUT);

  pinMode(AnalogBlueFloods, OUTPUT);
  pinMode(DigitalExternalTempLED, OUTPUT);
  pinMode(DigitalOilLevelLED, OUTPUT);
  pinMode(DigitalVibrationLED, OUTPUT); 
  pinMode(DigitalArduinoPowerLED, OUTPUT); 
  pinMode(DigitalRouterPowerLED, OUTPUT); 
  pinMode(DigitalInternalTempLEDred, OUTPUT); 
  pinMode(DigitalInternalTempLEDgreen, OUTPUT); 
  pinMode(DigitalInternalTempLEDblue, OUTPUT); 
  pinMode(DigitalRouterPower, OUTPUT); 
  pinMode(DigitalRouterStatusLEDYellow, OUTPUT); 
  pinMode(DigitalRouterStatusLEDGreen, OUTPUT); 
  pinMode(DigitalRouterStatusLEDRed, OUTPUT);

  digitalWrite(DigitalArduinoPowerLED, HIGH);
  AnalogWrite(AnalogBlueFloods, 255);
  Serial.begin(9600);

   // start the SPI library:
  SPI.begin();

  dht.begin();

  // Valid Admin States are: 0 = Normal (ON), 1 = Reboot, 2 = Shut-off, 3 = Series Reboot
  AdminState =  0;  
  if(AdminState == 0) {
    digitalWrite(DigitalRouterPower, HIGH);
    digitalWrite(DigitalRouterStatusLEDYellow, LOW);
    digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
    digitalWrite(DigitalRouterStatusLEDRed, LOW);
    SleepTime = 10000;
    digitalWrite(DigitalRouterPower, HIGH);
    for(i = 0; i < SleepTime; i = i + 1000) {
      if(Spinner == 0) {
        digitalWrite(DigitalRouterPowerLED, HIGH);
        Spinner = 1;
      } else {
        digitalWrite(DigitalRouterPowerLED, LOW);
        Spinner = 0;
      }
      delay(1000);
    }

  } else if(AdminState == 1) {
    SleepTime = 30000;
    digitalWrite(DigitalRouterPower, LOW);
    for(i = 0; i < SleepTime; i = i + 1000) {
      if(Spinner == 0) {
        digitalWrite(DigitalRouterPowerLED, HIGH);
        Spinner = 1;
      } else {
        digitalWrite(DigitalRouterPowerLED, LOW);
        Spinner = 0;
      }
      delay(1000);
    }
    digitalWrite(DigitalRouterPower, HIGH);
    digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    digitalWrite(DigitalRouterStatusLEDRed, LOW);
    AdminState = 0;
  } else if(AdminState == 2) {
    if(POWER_INTERRUPT == 1) { 
      digitalWrite(DigitalRouterPower, LOW);
    }
    digitalWrite(DigitalRouterStatusLEDYellow, LOW);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    digitalWrite(DigitalRouterStatusLEDRed, HIGH);
  } else if(AdminState == 3) {
    if(POWER_INTERRUPT == 1) { 
      digitalWrite(DigitalRouterPower, LOW);
    }
    for(i = 0; i < SeriesDelay; i = i + 1000) {
      if(Spinner == 0) {
        digitalWrite(DigitalRouterPowerLED, HIGH);
        Spinner = 1;
      } else {
        digitalWrite(DigitalRouterPowerLED, LOW);
        Spinner = 0;
      }
      delay(100);
    }
    digitalWrite(DigitalRouterPowerLED, HIGH);
    digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    digitalWrite(DigitalRouterStatusLEDRed, LOW);
    delay(SeriesDelay);
    digitalWrite(DigitalRouterPower, HIGH);
    AdminState = 0;
  } else {
    digitalWrite(DigitalRouterPower, HIGH);
  }

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();

  digitalWrite(DigitalRouterStatusLEDRed, HIGH);
  digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
  digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
  digitalWrite(DigitalInternalTempLEDgreen, HIGH);
  digitalWrite(DigitalInternalTempLEDred, HIGH);
  digitalWrite(DigitalInternalTempLEDblue, HIGH);


  // Now set the Flex sensor baseline
  digitalWrite(DigitalOilLevelLED, LOW);

  FlexTest1 = analogRead(AnalogFlexSensor);
  delay(pinReadDelay);
  SleepTime = 1000;
  for(k = 0; k < SleepTime; k = k + 100) {
    if(Spinner == 0) {
      digitalWrite(DigitalOilLevelLED, HIGH);
      Spinner = 1;
    } else {
      digitalWrite(DigitalOilLevelLED, LOW);
      Spinner = 0;
    }
    delay(100);
  }
  sprintf(buf, "Flex Baseline Test #1: %d", FlexTest1);
  Serial.println(buf);

  FlexTest2 = analogRead(AnalogFlexSensor);
  delay(pinReadDelay);
  SleepTime = 1000;
  for(k = 0; k < SleepTime; k = k + 100) {
    if(Spinner == 0) {
      digitalWrite(DigitalOilLevelLED, HIGH);
      Spinner = 1;
    } else {
      digitalWrite(DigitalOilLevelLED, LOW);
      Spinner = 0;
    }
    delay(100);
  }
  sprintf(buf, "Flex Baseline Test #2: %d", FlexTest2);
  Serial.println(buf);

  FlexTest3 = analogRead(AnalogFlexSensor);
  delay(pinReadDelay);
  SleepTime = 1000;
  for(k = 0; k < SleepTime; k = k + 100) {
    if(Spinner == 0) {
      digitalWrite(DigitalOilLevelLED, HIGH);
      Spinner = 1;
    } else {
      digitalWrite(DigitalOilLevelLED, LOW);
      Spinner = 0;
    }
    delay(100);
  }
  sprintf(buf, "Flex Baseline Test #3: %d", FlexTest3);
  Serial.println(buf);
  
  FlexBaseline = ((FlexTest1 + FlexTest2 + FlexTest3) / 3);
  FlexAlarmLevel = (FlexBaseline + 25);
  sprintf(buf, "Flex Baseline set to: %d, Alarm Level set to: %d", FlexBaseline, FlexAlarmLevel);
  Serial.println(buf);


}
 




void ListenForClients(void)
{
  // listen for incoming clients
  Client client = server.available();
  if (client) {
    Serial.println("Got a client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<meta http-equiv=\"refresh\" content=\"30\">");
          
          // print the current readings, in HTML format:
          client.print("" + String());
          client.println("RiderTrack Network Version: \n" + String(VERSION));
          client.println("<br />");
          client.println("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n");
          client.println("<br />");
          if(IDENTITY == 0) {
            client.println("Current Status for Node: mbf-wan-core (Kortrights)");
          } else if (IDENTITY == 1) {
            client.println("Current Status for Node: mbf-wan-edge1 (Garage)");
          } else if (IDENTITY == 2) {
            client.println("Current Status for Node: mbf-wan-edge2 (Boarders Tackroom)");
          } else if (IDENTITY == 3) {
            client.println("Current Status for Node: mbf-wan-barn (Main Barn)");
          } else if (IDENTITY == 4) {
            client.println("Current Status for Node: mbf-wan-edge3 (Feed Room)");
          } else if (IDENTITY == 5) {
            client.println("Current Status for Node: mbf-wan-edge4 (Barn Office)");
          } else if (IDENTITY == 6) {
            client.println("Current Status for Node: mbf-wan-edge5 (Hutchesons)");
          } else if (IDENTITY == 7) {
            client.println("Current Status for Node: mbf-wan-backup (Any Location)");
          } else {
            client.println("Current Status for Node: mbf-wan-backup (Any Location)");
          }
          client.println("<br />");
          client.print("Loop Count: " + String(Loopy));
          client.println("<br />");
          client.print("Series Delay: " + String(SeriesDelay));
          client.println("<br />");
          client.println("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
          client.println("<br />");
          if(AdminState == 0) {
            client.println("Admin Status: OK");
          } else if(AdminState == 1) {
            client.println("Admin Status: Rebooting");
          } else if(AdminState == 2) {
            client.println("Admin Status: Shut-Down");
          } else if(AdminState == 3) {
            client.println("Admin Status: Series-Rebooting");
          } else {
            client.println("Admin Status: Unknown");
          }
          client.println("<br />");
          if(SystemState == 0) {
            client.println("System Status: ON");
          } else if(SystemState == 1) {
            client.println("System Status: OFF");
          }
          client.println("<br />");
          if(RouterState == 0) {
            client.println("Router Status: ON");
          } else if(RouterState == 1) {
            client.println("Router Status: OFF");
          }
          client.println("<br />");
          if(FluidState == 0) {
            client.println("Fluid Status: OK");
          } else if(FluidState == 1) {
            client.println("Fluid Status: ALARM");
          }
          client.println("<br />");
          if(TempState == 0) {
            client.println("Temp Status: Normal");
          } else if(TempState == 1) {
            if(InternTempF < 32) {
              client.println("Temp Status: COLD");
            } else if(InternTempF > 100) {
              client.println("Temp Status: HOT");
            } else {
              client.println("Temp Status: Normal");
            }
          } else if(TempState == 2) {
            if(InternTempF < 0) {
              client.println("Temp Status: FROZEN");
            } else {
              client.println("Temp Status: BOILING");
            }
          }
          client.println("<br />");
          client.print("Air Temperature: " + String(ExternTempF));
          client.println("<br />");
          client.print("Oil Temperature: " + String(InternTempF));
          client.println("<br />");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1000);
    // close the connection:
    client.stop();
  }
}




/* xyzzy */

void loop()
{
  uint8_t i;
  float average;
  float ExternTemp;
  float DHTtemp, DHTtempRaw, DHThumidity;
  float ThermistorTempC, ExternTempF;
  int DHTtempF, InternTempC, InternTemp;
  int SleepTime = 0;
  int Spinner = 0;
  int LightLevelFlag = 0;
  int TiltSensor = 0;
  int TiltSensorRaw = 0;
  int TempCount = 0;
  int SetTempRecovery = 0;
  int x, k, d;
  int AverageTemp;
  int BANNED = 0;
  char buf[128];
  int tf;
  

  SetTempRecovery = 0;
  sprintf(buf, "  ");
  Serial.println(buf);
  Loopy = Loopy + 1;
  sprintf(buf, "Loop: %d", Loopy);
  Serial.println(buf);

  if(AdminState == 2) {
    digitalWrite(DigitalRouterStatusLEDYellow, LOW);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    digitalWrite(DigitalInternalTempLEDblue, LOW);
    digitalWrite(DigitalInternalTempLEDgreen, LOW);
    SleepTime = 2500;
    Spinner = 0;
    for(k = 0; k < SleepTime; k = k + 100) {
      if(Spinner == 0) {
        digitalWrite(DigitalRouterStatusLEDRed, HIGH);
        if(FluidState == 1) {
          analogWrite(DigitalOilLevelLED, 255);
        }
        Spinner = 1;
      } else {
        digitalWrite(DigitalRouterStatusLEDRed, LOW);
        if(FluidState == 1) {
          digitalWrite(DigitalOilLevelLED, 0);
        }
        Spinner = 0;
      }
      delay(100);
    }
  } 

  // =-=-= DHT Temp/Humidity Sensor =-=-=
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  DHThumidity = dht.readHumidity();
  DHTtempRaw = dht.readTemperature();

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(DHTtemp) || isnan(DHThumidity)) {
    Serial.println("Failed to read from DHT");
  } else {
    
    // DHTtemp = (((DHTtempRaw - .5) * 100) * 1.8) + 32;
    DHTtemp = ((1.8 * DHTtempRaw) + 32);
    DHTtempF = int(DHTtemp);

    Serial.print("Humidity: ");
    Serial.print(DHThumidity);
    Serial.print(" %\t");
    Serial.print("Temperature: ");
    Serial.print(DHTtempF);
    Serial.println(" *F");
  }

  // =-=-= Internal Temp Sensor =-=-=
  // =-=-= Thermistor Sensor =-=-=
  // take N samples in a row, with a slight delay
  for (d=0; d< NUMSAMPLES; d++) {
   samples[d] = analogRead(AnalogThermistorSensor);
   delay(pinReadDelay);
  }
 
  // average all the samples out
  average = 0;
  for (d=0; d< NUMSAMPLES; d++) {
     average += samples[d];
  }
  average /= NUMSAMPLES;

  Serial.print("Average thermistor analog reading: "); 
  Serial.println(average);
 
  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  Serial.print("Thermistor resistance: "); 
  Serial.println(average);
 
  float steinhart;
  steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                         // convert to C
  // steinhart -= ThermistorOffset;

/*
  if((steinhart < 20) && (steinhart > 15)) {
    steinhart -= 2;
  } else if((steinhart < 16) && (steinhart > 10)) {
    steinhart -= 4;
  } else if((steinhart < 11) && (steinhart > 5)) {
    steinhart -= 6;
  } else if((steinhart < 6) && (steinhart > 0)) {
    steinhart -= 8;
  } else if((steinhart > 30) && (steinhart < 35)) {
    steinhart += 1;
  } else if((steinhart > 34) && (steinhart < 40)) {
    steinhart += 2;
  } else if((steinhart < 39) && (steinhart > 45)) {
    steinhart += 3;
  } else if((steinhart < 44) && (steinhart > 50)) {
    steinhart += 4;
  }
*/

  float temperatureF = (steinhart * 1.8) + 32.0;
  Serial.print("Thermistor Temperature in C: "); 
  Serial.print(steinhart);
  Serial.println(" *C");
  Serial.print("Thermistor Temperature in F: "); 
  Serial.print(temperatureF);
  Serial.println(" *F");
  InternTempF = int(temperatureF);


  if (InternTempF < -10) {
    digitalWrite(DigitalInternalTempLEDblue, LOW);
    digitalWrite(DigitalInternalTempLEDgreen, HIGH);
    digitalWrite(DigitalInternalTempLEDred, HIGH);
    TempAlarms = TempAlarms + 1;

    if((TempAlarms > MAX_TEMP_ALARMS) && (TempState < 2)) {
      // XYZZY: need to send an alarm to Netcool HERE, Too COLD!! O_O
      sprintf(buf, "Cold Temperature Critical! System freezing up!");
      Serial.println(buf);
      sprintf(buf, "Disconnecting power to router/pump/heater!");
      Serial.println(buf);
      digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      digitalWrite(DigitalRouterStatusLEDRed, LOW);
      digitalWrite(DigitalInternalTempLEDblue, LOW);
      if(POWER_INTERRUPT == 1) {
        digitalWrite(DigitalRouterPower, LOW);
      }
      SystemState = 1;
      AdminState = 2;
      TempState = 2;
    } else {
      sprintf(buf, "Oil Temperature too Cold!");
      Serial.println(buf);
      
      Spinner = 0;
      for(k = 0; k < 1000; k = k + 100) {
        if(Spinner == 0) {
          digitalWrite(DigitalInternalTempLEDblue, HIGH);
          Spinner = 1;
        } else {
          digitalWrite(DigitalInternalTempLEDblue, LOW);
          Spinner = 0;
        }
        delay(100);
      }
      digitalWrite(DigitalInternalTempLEDblue, HIGH);
    }  
  } else if (InternTempF > 140) {
    digitalWrite(DigitalInternalTempLEDblue, HIGH);
    digitalWrite(DigitalInternalTempLEDgreen, HIGH);
    digitalWrite(DigitalInternalTempLEDred, LOW);
    digitalWrite(DigitalExternalTempLED, HIGH);
    TempAlarms = TempAlarms + 1;
    
    if((TempAlarms > MAX_TEMP_ALARMS) && (TempState < 2)) {
      // XYZZY: need to send an alarm to Netcool HERE, Too HOT!! O_O
      sprintf(buf, "Hot Temperature Critical! System is burning up!");
      Serial.println(buf);
      digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      digitalWrite(DigitalRouterStatusLEDRed, LOW);
      digitalWrite(DigitalInternalTempLEDred, LOW);
      if(POWER_INTERRUPT == 1) {
        digitalWrite(DigitalRouterPower, LOW);
      }
      SystemState = 1;
      AdminState = 2;
      TempState = 2;
    } else {
      sprintf(buf, "Oil Temperature too Hot!");
      Serial.println(buf);
      
      Spinner = 0;
      for(k = 0; k < 1000; k = k + 100) {
        if(Spinner == 0) {
          digitalWrite(DigitalRouterStatusLEDRed, HIGH);
          Spinner = 1;
        } else {
          digitalWrite(DigitalRouterStatusLEDRed, LOW);
          Spinner = 0;
        }
        delay(100);
      }
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    }  
  } else if(InternTempF < 40) {
    if(TempState == 2) {
      if(AdminState == 2) {
        if(SystemState == 1) {
          SetTempRecovery = 1;
        }
      }
    }
    digitalWrite(DigitalInternalTempLEDblue, LOW);
    digitalWrite(DigitalInternalTempLEDgreen, HIGH);
    digitalWrite(DigitalInternalTempLEDred, HIGH);
    digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
    TempState = 1;
    sprintf(buf, "Its too damn Cold in here! Temp < 40!");
    Serial.println(buf);
  } else if (InternTempF > 100.0) {
    if(TempState == 2) {
      if(AdminState == 2) {
        if(SystemState == 1) {
          SetTempRecovery = 1;
        }
      }
    }
    digitalWrite(DigitalInternalTempLEDblue, HIGH);
    digitalWrite(DigitalInternalTempLEDgreen, HIGH);
    digitalWrite(DigitalInternalTempLEDred, LOW);
    digitalWrite(DigitalRouterStatusLEDYellow, LOW);
    TempState = 1;
    sprintf(buf, "Its too BANNED Hot in here man! Temp > 100!");
    Serial.println(buf);
  } else {
    if(TempState == 2) {
      if(AdminState == 2) {
        if(SystemState == 1) {
          SetTempRecovery = 1;
        }
      }
    }
    if(TempState == 1) {
      sprintf(buf, "Exterior tempeature returned to normal range (%d)", ExternTempF);
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalInternalTempLEDblue, HIGH);
      digitalWrite(DigitalInternalTempLEDgreen, LOW);
      digitalWrite(DigitalInternalTempLEDred, HIGH);
      TempState = 0;
    }
  }
  if(SetTempRecovery == 1) {
    sprintf(buf, "Internal Oil tempeature returned to normal range!");
    Serial.println(buf);
    sprintf(buf, "Starting router/pump/heater power!");
    Serial.println(buf);
      
    TempState = 0;
    TempAlarms = 0;
    AdminState = 0;
    if(SystemState == 1) { 
      sprintf(buf, "Tempeature returned to normal range, re-activating power!", TiltSensorRaw);
      Serial.println(buf);
      digitalWrite(DigitalRouterPower, HIGH);
      SystemState = 0;
    }
    SetTempRecovery = 0;
    digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
    digitalWrite(DigitalRouterStatusLEDGreen, LOW);
    if(RouterState == 0) {
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    }
  }





  // =-=-= Light (power) Sensor =-=-=
  int LightLevel = analogRead(AnalogPhotoCellRouter);
  delay(pinReadDelay);
  LightLevel = map(LightLevel, 0, 900, 0, 10); 
  LightLevel = constrain(LightLevel, 0, 10);
  if(LightLevel > 4) {
    if(RouterState == 0) {
      if(RouterPowerState == 0) {
        digitalWrite(DigitalRouterPowerLED, HIGH);
      }
      RouterPowerState = 1;
      sprintf(buf, "Router power is ON (sensor: %d)", LightLevel);
      Serial.println(buf);
    } else {
      digitalWrite(DigitalRouterPowerLED, HIGH);
      RouterPowerState = 1;
      sprintf(buf, "Router power is ON, it must have recovered! (sensor: %d)", LightLevel);
      Serial.println(buf);
      // XYZZY: Send an Recovery alarm to Netcool HERE.
      RouterState = 0;
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalRouterStatusLEDGreen, LOW);
      digitalWrite(DigitalRouterStatusLEDRed, LOW);
    }
  } else {
    if(AdminState == 0) {
      digitalWrite(DigitalRouterPowerLED, LOW);
      sprintf(buf, "Router power is OFF and should be ON!(sensor: %d)", LightLevel);
      Serial.println(buf);
      // XYZZY: Send an alarm to Netcool HERE.
      RouterState = 1;
      RouterPowerState = 0;
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalRouterStatusLEDGreen, LOW);
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    } else {
      digitalWrite(DigitalRouterPowerLED, LOW);
      sprintf(buf, "Router power is OFF (sensor: %d)", LightLevel);
      Serial.println(buf);
    }
  }

  // =-=-= Tilt Sensor =-=-=
  TiltSensorRaw = analogRead(AnalogFlexSensor);
  delay(pinReadDelay);
  sprintf(buf, "Raw Flex Resistance: %d, Alarm Level is: %d, Delta = %d", TiltSensorRaw, FlexAlarmLevel, (FlexAlarmLevel - TiltSensorRaw));
  Serial.println(buf);

  if((TiltSensorRaw > FlexAlarmLevel) || (ReverseTiltMode == 1)) {
    TiltSensor = 1;
  } else {
    TiltSensor = 0;
  }
  if(TiltSensor == 0) {
    analogWrite(DigitalOilLevelLED, 0);
    Tilts = 0;

    if(FluidState == 1) {
      sprintf(buf, "Fluid Level Test: PASS! (raw: %d)", TiltSensorRaw);
      Serial.println(buf);
      FluidState = 0;
      if(AdminState == 2) {
        AdminState = 0;
        if(SystemState == 1) { 
          // XYZZY - Send tilt Recovery trap to Netcool.
          sprintf(buf, "Fluid levels Restored!, re-activating Power!", TiltSensorRaw);
          Serial.println(buf);
          digitalWrite(DigitalRouterPower, HIGH);
          SystemState = 0;
        } else {
        // XYZZY - Send tilt Recovery trap to Netcool.
        }
      } else {
        // XYZZY - Send tilt Recovery trap to Netcool.
      }
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      if(RouterState == 0) {
        digitalWrite(DigitalRouterStatusLEDRed, LOW);
      }
    } else {
      // XYZZY - Send tilt Recovery trap to Netcool.
      sprintf(buf, "Fluid Level Test: PASS");
      Serial.println(buf);
      Tilts = 0;
    }
  } else {
    analogWrite(DigitalOilLevelLED, 255);
    Tilts = Tilts + 1;

    if(Tilts >= MAX_TILT_ALARMS) {
      // XYZZY: need to send an alarm to Netcool HERE, were out of fluid!! O_O
      sprintf(buf, "Fluid Level Alarm!! Router is out of Oil!");
      Serial.println(buf);
      sprintf(buf, "Disconnecting power to router, pump and heater!");
      Serial.println(buf);
      analogWrite(DigitalOilLevelLED, 255);
      digitalWrite(DigitalRouterStatusLEDYellow, LOW);
      digitalWrite(DigitalRouterStatusLEDGreen, LOW);
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
      Spinner = 0;
      for(k = 0; k < 1000; k = k + 100) {
        if(Spinner == 0) {
          analogWrite(DigitalOilLevelLED, 255);
          Spinner = 1;
        } else {
          analogWrite(DigitalOilLevelLED, 0);
          Spinner = 0;
        }
        delay(100);
      }
      analogWrite(DigitalOilLevelLED, 255);
      if(POWER_INTERRUPT == 1) {
        digitalWrite(DigitalRouterPower, LOW);
      }
      SystemState = 1;
      AdminState = 2;
      FluidState = 1;
    } else if((Tilts > 4) && (Tilts < MAX_TILT_ALARMS)) {
      // XYZZY: need to send an alarm to Netcool HERE, were out of fluid!! O_O
      sprintf(buf, "Fluid Level Alarm! (Tilts: %d)", Tilts);
      Serial.println(buf);
      
      analogWrite(DigitalOilLevelLED, 255);
    } else {
      // XYZZY: need to send an alarm to Netcool HERE, were out of fluid!! O_O
      sprintf(buf, "Fluid Sensor has moved! (Tilts: %d), Raw: %d", Tilts, TiltSensorRaw);
      Serial.println(buf);
      
      Spinner = 0;
      for(k = 0; k < 1000; k = k + 100) {
        if(Spinner == 0) {
          analogWrite(DigitalOilLevelLED, 255);
          Spinner = 1;
        } else {
          analogWrite(DigitalOilLevelLED, 0);
          Spinner = 0;
        }
        delay(100);
      }
      analogWrite(DigitalOilLevelLED, 0);
    }
  }
 



  // =-=-= Vibration Sensor =-=-=
/*
  BANNED = analogRead(AnalogVibrationSensor);
  delay(pinReadDelay);
  Serial.print("Raw Vibration Sensor Reading: "); 
  Serial.print(BANNED);
  Serial.println(".");
*/

  vfd.clear();

  int temp = int(DHTtempF);
  int humidity = int(DHThumidity);
  sprintf(buf, "Temp: %dF  Hum: %d%%", temp, humidity);
  vfd.setCursor(0, 0);
  vfd.print(buf);

  if(AdminState == 2) {
    sprintf(buf, "Emergency Shutdown!");
  } else if(FluidState == 1) {
    sprintf(buf, "Oil Level Low/Out!");
  } else if(TempState == 1) {
    if(InternTempF > 0) {
      sprintf(buf, "Alarm: Oil Temp High");
    } else {
      sprintf(buf, "Alarm: Oil Temp Low");
    }
  } else if(TempState == 2) {
    if(InternTempF > 0) {
      sprintf(buf, "PANIC! Oil Temp High");
    } else {
      sprintf(buf, "PANIC! Oil Temp Low");
    }
  } else if(RouterState == 1) {
    sprintf(buf, "Router Power Off?!");
  } else {
    sprintf(buf, "All is Good at MBF!");
  }
  vfd.setCursor(0, 1);
  vfd.print(buf);


  // Now determine final LED state
  if(AdminState == 0) {
    if(RouterState == 0) {
      digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
      digitalWrite(DigitalRouterStatusLEDGreen, LOW);
      delay(100);
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      digitalWrite(DigitalArduinoPowerLED, HIGH);
      delay(100);
      digitalWrite(DigitalArduinoPowerLED, LOW);
      digitalWrite(DigitalRouterPowerLED, HIGH);
      delay(100);
      digitalWrite(DigitalRouterPowerLED, LOW);
      digitalWrite(DigitalInternalTempLEDgreen, LOW);
      digitalWrite(DigitalInternalTempLEDred, LOW);
      delay(100);
      digitalWrite(DigitalInternalTempLEDgreen, HIGH);
      digitalWrite(DigitalInternalTempLEDred, HIGH);
      digitalWrite(DigitalExternalTempLED, HIGH);
      delay(100);
      digitalWrite(DigitalExternalTempLED, LOW);
      delay(100);
      digitalWrite(DigitalOilLevelLED, HIGH);
      delay(100);
      digitalWrite(DigitalOilLevelLED, LOW);
      delay(100);
      digitalWrite(DigitalVibrationLED, HIGH);
      delay(100);
      digitalWrite(DigitalVibrationLED, LOW);
      delay(100);

    } else {
      digitalWrite(DigitalRouterStatusLEDGreen, HIGH);
      digitalWrite(DigitalRouterStatusLEDRed, LOW);
      digitalWrite(DigitalRouterStatusLEDYellow, HIGH);
      SleepTime = 1000;
      for(k = 0; k < SleepTime; k = k + 100) {
        if(Spinner == 0) {
          digitalWrite(DigitalRouterPowerLED, HIGH);
          digitalWrite(DigitalRouterStatusLEDRed, HIGH);
          Spinner = 1;
        } else {
          digitalWrite(DigitalRouterPowerLED, LOW);
          digitalWrite(DigitalRouterStatusLEDRed, LOW);
          Spinner = 0; 
        }
        delay(100);
      }
      digitalWrite(DigitalRouterStatusLEDRed, HIGH);
    }
  }

  sprintf(buf, "SystemState: %d, AdminState: %d, FluidState: %d, TempState: %d", SystemState, AdminState, FluidState, TempState);
  Serial.println(buf);
  for(d=0;d<=100;d++) {
    ListenForClients();
    delay(10);
  }
}


float getVoltage(int pin) {
  return (analogRead(pin) * .004882814); 
}
I know my code could be better :mrgreen: - It's really been lack of time to make it nice and efficient. It works well though, so in this case; function over form. :wink:

Its for this very reason that my friend and work colleage; Mike Bush, is doing all the code for RiderNet and setup the RiderTrack server operating system and configurations - so that will be top form.

More to come, I have to waterproof the cable ends - we're expecting big rains later this week - the first field test. ;)

Kris

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

Some updated screenshots, this one of the Tree router at night (kinda hard to see, camera is so-so in the dark):
Tree router at night
Tree router at night
TreeHouse_Night_Small.jpg (307.73 KiB) Viewed 12051 times
The next screenshots are of the router at the Other end of the main barn in daytime:
Other end of the main barn
Other end of the main barn
Mainbarn_End_Day_Small.JPG (353.37 KiB) Viewed 12051 times
And a close-up of the same router at night:
End of main barn router at night
End of main barn router at night
Mainbarn_End_Night.jpg (177.65 KiB) Viewed 12051 times
My camera does not do night-shots justice, so I plan to try my video recorder - I think the moving LEDs are more impressive then, and perhaps the video camera will do better in low-light.

More to come!

Kris

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

Update: Challenges, Solutions and a milky-router!

During the last 10 days I've hit my first challenges with RiderNet, most of which are overcome but one is rather amusing.

1. Of all the Netgear WNDR3300 WIFI routers I got, two of them had different power supplies from the rest. I only used one of these in the mineral-oil routers (thank goodness). Well, on Saturday morning I went down to the barn to do morning work and this particular router looked as though it was filled with BANNED. :lol: I freaked-out of course, and stupidly did not take a picture :cry: . None the less it was amusing and turned out to be a white putty/paste substance used in the power supply to hold things together. I replaced this with one of the other supplies that doesn't have dissolvables in them and all was well on that front. :roll:

2. Signal strength is not good-enough between routers, which is more of a defficiency in the older WNDR3300 routers but _could_ also be a consequence of using Mineral oil (here I am outside of my knowledge, I don't know if the less-dense mineral oil disrupts radio signals to any degree). In any case I needed more signal, and found the only solution was to literally solder tiny U.fl connectors onto the router motherboards, replacing an existing test connector, and then attach antenna's to that. I had seen this thread a year ago, but at the time had no ability to Do the modification. Now however, after Arduino and Adafruit tutorials, I was much more couragous to try. The thread is here:

http://www.dd-wrt.com/phpBB2/viewtopic. ... na&start=0

My camera can't do justice to the small scale, so here are a couple of photos from that thread that illustrate how small the surface mount antennas are:
U.fl connectors replacing test connectors on the WNDR3300
U.fl connectors replacing test connectors on the WNDR3300
newconnectorswndr3300_108.jpg (166.17 KiB) Viewed 11592 times
On a cased WNDR3300 router the result looks like this (3 Antennas for the dual-band radio and 2 Antennas for the 2nd 2.4 gig-only radio):
cased WNDR3300 with antennas
cased WNDR3300 with antennas
extantennaswndr3300_649.jpg (153.15 KiB) Viewed 11592 times
Now on my showcase RiderNet router with the VFD :)
RiderNet router with Antennas
RiderNet router with Antennas
RiderNet3_Antennas2_small.jpg (270.47 KiB) Viewed 11592 times
The result for the first successful attempt to add antennas is Good - signal strength improved dramatically! However, the journey to get to this point was no happy fun ball... (next post)

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

RiderNet Update: Newbie vs. SMD (Round 1)

Per the previous post, I had to add more signal strength to the RiderNet network - but adding Antennas to a mineral-oil cased Wifi router is very challenging. For one I had to solder SMD components for the first time, which is hugely challenging (at least it was for me). I also had to acquire the bits, which I now felt Much more comfortable doing with my short experience in the DIY community - the magic of Digi-Key is not to be under-estimated! For the record I am a big Digi-Key fan. 8) They have the exact Antennas and the SMD U.FL connectors that I needed to use for the WNDR3300 radio:

http://search.digikey.com/us/en/product ... -ND/513010

http://search.digikey.com/scripts/DkSea ... ND&x=0&y=0

http://search.digikey.com/scripts/DkSea ... ND&x=0&y=0

The only part they did not have was the pigtail needed to connect from the U.FL connector on the motherboard to the Antennas themselves, which I found at wisp-router:

http://store.wisp-router.com/catalog/pa ... RPSMAFB-.8

These bits together work very well, my house router (the core) can even see the router with antennas at the mainbarn (at 2-3%), which is through a house, a metal barn wall and a forest. Yeehah! :D

But soldering SMD... Wow, this is hard stuff. :shock: Here are some pics of just how bad my first attempts were, and a close-up of the one working result. First the router close-up:
Close-up of the RiderNet router with Antennas. Note the U.FL pigtails connecting from the motherboard to the top where the Antennas connect.
Close-up of the RiderNet router with Antennas. Note the U.FL pigtails connecting from the motherboard to the top where the Antennas connect.
RiderNet3_Antennas1.jpg (449.37 KiB) Viewed 11592 times
And this is my Second attempt at soldering these little u.fl connectors to the Wifi router.. The first attempt was so bad that some connectors got mashed, some accidentally filled with solder (lol), some I had to tweak and tweak until the connectors on the motherboard were gone.. This second attempt was is still BAD, but I started using the right tools (the close-up visor from Adafruit and the tweezers with the super-fine tips). Those tweezers are must-have for SMD (at least to me, after trying with larger tools). I needed finer solder so I got some coming. My ONLY excuse for this horrible work is that my Hakko was bareful functional and not that hot, the tip wasn't even hot enough to melt the solder quickly. It was a rough weekend..
My second attempt at soldering SMD. :(
My second attempt at soldering SMD. :(
RiderNet_SmdSuckage.jpg (493.64 KiB) Viewed 11592 times
So! With this epic failure with tiny success at the end past, I'm ready for Round 2 this weekend. I have more u.fl connectors from Digi-key on the way, got plenty of spares this time. Once I have the new Hakko from Adafruit and the finer solder, I think I'll be ready... I predict a loss rate of 33% or so %, versus the 60% loss rate last weekend :roll:

Is there any input or advice anyone could share about how to solder SMD correctly? I'm learning by doing, but its costly in time and parts!

Thanks. :)

Kris

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

RiderNet Update: Newbie vs. SMT (Round 2)

I practiced on the 3 initial routers I had soldered - all 3 of those were sacrificed to the Gods of hacking, the experience was worth it. Thanks to the Magic of Ebay, I was able to replace all 3 at $12 a pop! :lol:

After that and receiving the rest of the SMT U.FL connectors, whips and antennas, I was ready to manufacture 6 production versions (30 total SMT removals of old, adding 30 of the new U.FL connectors). It was many hours later and a few late nights this week, but all 6 of the mineral oil WIFI routers now have 5 U.FL antennas mounts. :) My camera can't get down to the level of detail that would make the photo's really clear, but I did the best I could - all in all every connector is soldered at all 4 points with a clean antenna solder point at the top. Not all of them were as clean and neat as I want, but using the Adamagnifiers I am able to verify that the connections are made and don't bleed-out into other spots or the ground plain:
Close-up of my latest attempts at SMT soldering.
Close-up of my latest attempts at SMT soldering.
RiderNet2.1NewWifi1.jpg (315.48 KiB) Viewed 12244 times
When affixed with their pigtails and antennas, the completed board looks like:
Complete Wifi router with Antennas
Complete Wifi router with Antennas
RiderNet2.1NewWifi2.jpg (168.61 KiB) Viewed 12244 times
And all 6 on the table, completed a few hours ago:
All 6 of the completed Wifi routers with Antennas
All 6 of the completed Wifi routers with Antennas
RiderNet2.1NewWifi3.jpg (348.37 KiB) Viewed 12244 times
After my experience with SMT the first time, I have realized that I have alot to learn about it still, and it's damn hard working with such small things!

Next update will be about the Xbee OOB (out of band) management channel I've created between the routers, and a sketch that allows them to talk and coordinate. Just have to document it. :)

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

Good Morning!

I am overdue for an update on RiderNet - there have been big changes since v2 was released, including the creation/inclusion of a new network protocol for Arduino Mega's to talk back and forth using Xbees (UNO version will come once the Mega version is optimized for smallness). I'm calling it XNP (Xbee Network Protocol), and am including examples and documentation in the code for how others can make use of it.

I also had to create new Proto shields to connect everything together, moving the sensors onto a 3.3v bus and keeping the Xbee, Power Shwitch Tail and LEDs on the 5v bus. New more efficient wiring arrangements are allowing me to create the boards more easily (making 10 total, need 6 for production and sending 2 to back to my source of inspiration :wink:

The antenna mounts (including on the Xbees) are completed along with a new rain shield to help keep the elements out. I also added X10 PowerLine support to the routers, so that through XNP I can reboot things in different parts of the barn. The biggest update is the code re-write, the entire sketch had to be rebuilt and modularized (new more efficient sensor module, XNP functions, better control logic). Its sitting at around ~2500 lines of code right now with both XNP and the 5-sensor module all working together - and I still have free memory to boot. :)

I will do a more formal post on all of this later in the week - I need to finish the new proto boards and resolve 2 minor issues with XNP before I'm ready to publish.

Stay Tuned!

Kris

User avatar
miax
 
Posts: 157
Joined: Tue Apr 05, 2011 11:41 am

Re: RiderNet V2 - an All-Weather Arduino-Managed WiFi Network

Post by miax »

RiderNetV2 Update: New Circuit Boards!

After 3 weeks the new RiderNetV2 circuit boards are completed and ready for deployment. I created a total of 10 circuit boards for the new routers, which had me going through a micro-manufacturing process of sorts that actually helped me spot problems and fix them before the first tests. I used NKC Mega Proto shields that I got from Adafruit (http://www.adafruit.com/products/192) and Amazon (used to sell the bare PCB, no longer), and the Adafruit Xbee Adapter (http://www.adafruit.com/products/126) using a Series 1 Xbee (http://www.adafruit.com/products/128). I got the LEDs, header, connectors and resistors from Jameco and Digikey which I now get in bulk to bring the prices of all this down a little. I made a total of 11 mistakes in creating the circuit boards, each of which had to be backed-out/fixed on all 10 (the price of still being new to the field). In the end by making them in bulk, they all worked exactly the same once the bugs were worked out. Below are screenshots and a diagram I knocked-out to describe the new circuit boards:
RiderNetV2 Circuit Board Diagram
RiderNetV2 Circuit Board Diagram
RiderNet2_PCBdiagram.JPG (780.31 KiB) Viewed 14014 times
Profile Shots with Xbees/Adapters/Sensors attached:
RiderNetV2 Circuit Board profile shot
RiderNetV2 Circuit Board profile shot
RiderNet2_ProtoProfile.JPG (665.29 KiB) Viewed 14014 times
Manufactured and ready for deployment/shipment!
RiderNetV2 Circuit Boards - manufactured and ready for deployment
RiderNetV2 Circuit Boards - manufactured and ready for deployment
RiderNet2_ProtoAll10.JPG (589.63 KiB) Viewed 14014 times
These circuit boards have a number of advantages over my RiderNet V1 prototypes:

- Sensors run on a 3.3v bus with analog voltage reference to make them more accurate.
- Pin-outs are more logically grouped for easier cabling inside the routers
- Power switch tail port is now driven by dual-digital drive pins (so enough voltage is supplied for PST v1).
- New XNP packet LEDs were added to the circuit boards directly (where all others are exposed via a cable to a front panel).
- An adapter port was added for the Adafruit Xbee Adapters allowing a secure connection between them with dedicated wiring.
- Exposed the reset switch (yup).

The RiderNetV2 circuit boards were prototyped using the following tutorials by Lady Ada:

http://www.ladyada.net/make/xbee/
http://www.ladyada.net/learn/sensors/fsr.html
http://www.ladyada.net/learn/sensors/tmp36.html
http://www.ladyada.net/learn/sensors/thermistor.html
http://www.ladyada.net/learn/sensors/cds.html
http://www.ladyada.net/learn/sensors/tilt.html

Creating small sketches for each type of sensor allowed me to test them and work-out several bugs in boards, which was enormously helpful. I plan to deploy 6 of these boards to the field in the RiderNetV2 routers next weeend, with one in my office as the "Core" Xbee router that receives heartbeats from the RiderNet routers in the field, receives the sensor/run stats data from each and can command them/all to reboot their Wifi routers as necessary using the power switch tails. The other two I'm sending back to Adafruit as a token of Thanks for all the great products, support and tutorials which made RiderNet possible!

I resolved the last major bug in Xbee Network Protocol last night, and am hopeful I can post a follow-up with complete details on XNP and sketches sometime this week. I'm taking a bit longer on this because I want it to be as clean and bug-free as possible before releasing an alpha. :)

All feedback, comments and constructive criticism are most welcome!!

Cheers,

Kris

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”