Envico_Mainframe.php 18898 Bytes 20-06-2024 21:05:25
ENVICO®light Mainframe
Arduino® Shield "FLO"
Yet another Arduino™ datalogger project. This is the public version of our ENVICO™ system, used by ETH Quantumoptics.
The central data unit is based on an Arduino™ UNO, an ETHernet shield and a FLO shield.
All sensors report data via I2C™.
![ENVICO Mainframe, aka "Basestation"](https://www.changpuak.ch/electronics/Arduino/Shield/FLO-Indoor-unit.jpg)
The Basestation is the heart of this environmental data logging system. It is based on an
Arduino UNO™, an
ARDUINO ETHernet shield as well as an
FLO shield. All sensors report the data via a I2C link. It is
possible to connect four sensors to the basestation. The data storage as well as the visualisation is done by
thingspeak.com. Results can bee seen
here.
A sensor is connected via a sub-d 9 pin cable. This offers the possibility to supply it with +12V, +5V, I2C data, I2C clock, alarm and a gpio pin.
The I2C bus is switched with a 4052 logic switch, as a defective sensor usually blocks the bus - on the other hand you mayst use four identical
sensors, for e.g. the supervision of four deep-freezers (maybe in a restaurant).
Pinout of the DSUB-9 connector.
GPIO and ALARM are available in the professional version only. The sensors always have a male connector.
The alarm fuctionality allows to send sms / emails, in case a value runs out of a predefined window. It mayst be connected to an interlock
as well. Find more information on the
'professional' version at the
QSIT website.
The values of those four sensors are displayed on a 4x20 lcd for information. In case no meaningful value is available, the display
will read 'NESCIO'.
✈ Downloads (FLO shield)
✈ Arduino Sketch - The Code
Double click on code to select ...
/*
Envico light "Mainframe", aka Flo
22.06.2015 V1.1 by Alexander C. Frank
ETH Quantumoptics
*/
#include <Wire.h>
#include <SPI.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
#include <Ethernet.h>
// Local Network Settings
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0F, 0x6E, 0xB8 }; // Must be unique
// ThingSpeak Settings
char thingSpeakAddress[] = "api.thingspeak.com";
String writeAPIKey = "USEYOUROWNAPIKEY";
const int updateThingSpeakInterval = 32 * 1000; // Time interval
// Variable Setup
long lastConnectionTime = 0;
boolean lastConnected = false;
int failedCounter = 0;
// Initialize Arduino Ethernet Client
EthernetClient client;
// /////////////////////////////////////////////////////////////
// Function declarations
void UpDateSensorAtPortK10();
void UpDateSensorAtPortK8();
void UpDateSensorAtPortK7();
void UpDateSensorAtPortK6();
void UpDateDewPoint();
void UpDateCloudBase();
void Pause();
// Pin declarations
int LED = 13 ;
int SA = 3 ;
int SB = 2 ;
// Constants declarations;
byte Eeeprom = 0x50 ;
byte LuxSensor = 0x44 ;
byte Barometer = 0x60 ;
byte HumidityAddress = 0x28 ;
byte TemperatureAddress = 0x18 ;
// Global Variables declaration
int lumi = 0 ;
float humidity = 0 ;
float airpressure = 0 ;
float temperature = -99 ;
float HumidityIndex = 0 ;
float HeatIndex ;
float DewPoint ;
float CloudBase ;
char pressure[8];
char tempstring[8];
char HumidityString[8];
char HeatIndexString[8];
char DewPointString[8];
char CloudBaseString[8];
// /////////////////////////////////////////////////////////////
void setup()
{
// REDUCE SPEED OF I2C
// TWBR=1000;
Wire.begin();
Serial.begin(9600);
pinMode(LED, OUTPUT);
pinMode(SA, OUTPUT);
pinMode(SB, OUTPUT);
pinMode(A2, OUTPUT);
lcd.begin(16, 4);
lcd.clear();
// lcd.setCursor(0,0);lcd.print("GRUEZI :-)");
// Start Ethernet on Arduino
startEthernet();
// INIT LUXSENSOR
Wire.beginTransmission(LuxSensor);
Wire.write(0x00); // Command
Wire.write(B10000100);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(LuxSensor);
Wire.write(0x01); // Control
Wire.write(B00001100);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(LuxSensor);
Wire.write(0x02); // High byte of HI interrupt threshold.
Wire.write(0xFF);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(LuxSensor);
Wire.write(0x03); // High byte of LO interrupt threshold.
Wire.write(0x00);
Wire.endTransmission();
delay(234);
// Serial.print("LUX Sensor Test\n");
}
// /////////////////////////////////////////////////////////////
// Select DSUB K6, SD_0 and SC_0
// LUMINANCE
void UpDateSensorAtPortK6()
{
digitalWrite(SA, LOW);
digitalWrite(SB, LOW);
digitalWrite(A2, LOW);
lcd.setCursor(0,0);lcd.print("LUMI: ");
Wire.beginTransmission(LuxSensor);
Wire.write(0x04);
Wire.endTransmission();
Wire.requestFrom(LuxSensor,2);
byte lux_lo = Wire.read();
byte lux_hi = Wire.read();
lumi = lux_hi ;
lumi = lumi << 8 ;
lumi = lumi | lux_lo ;
if (lumi >= 0 ) { lcd.print(lumi,DEC); lcd.print(" LUX "); }
else { lcd.print("NESCIO "); }
Pause();
}
// /////////////////////////////////////////////////////////////
// Select DSUB K7, SD_1 and SC_1
// HUMIDITY
void UpDateSensorAtPortK7()
{
digitalWrite(SA, HIGH);
digitalWrite(SB, LOW);
digitalWrite(A2, LOW);
Wire.requestFrom(HumidityAddress,2);
int hum_hi = Wire.read();
int hum_lo = Wire.read();
int humi = (( hum_hi << 8 ) | hum_lo ) & 0x3FFF ;
int ok = ( humi & 0xC000 ) >> 14 ;
humidity = humi * 100.0 / 16384 ;
lcd.setCursor(0,1);lcd.print("HUMI: ");
if (humidity > 1.0 ) { lcd.print(humidity,1); lcd.print(" %RH "); }
else { lcd.print("NESCIO "); }
dtostrf(humidity, 5, 2, HumidityString);
}
// /////////////////////////////////////////////////////////////
// Select DSUB K8, SD_2 and SC_2
// AIR PRESSURE
void UpDateSensorAtPortK8()
{
digitalWrite(SA, LOW);
digitalWrite(SB, HIGH);
digitalWrite(A2, LOW);
// START CONVERSION
Wire.beginTransmission(Barometer);
Wire.write(0x12);
Wire.write(0xAF);
Wire.endTransmission();
// WAIT FOR MEASUREMENT TO COMPLETE
delay(5); // max. 3 ms
// READ ALL MEMORY LOCATIOSN
Wire.beginTransmission(Barometer);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom(Barometer,12);
unsigned int Padc_MSB = Wire.read(); // 0x00
unsigned int Padc_LSB = Wire.read(); // 0x01
unsigned int Tadc_MSB = Wire.read(); // 0x02
unsigned int Tadc_LSB = Wire.read(); // 0x03
unsigned int a0_MSB = Wire.read(); // 0x04
unsigned int a0_LSB = Wire.read(); // 0x05
unsigned int b1_MSB = Wire.read(); // 0x06
unsigned int b1_LSB = Wire.read(); // 0x07
unsigned int b2_MSB = Wire.read(); // 0x08
unsigned int b2_LSB = Wire.read(); // 0x09
unsigned int c12_MSB = Wire.read(); // 0x0A
unsigned int c12_LSB = Wire.read(); // 0x0B
// COMBINE MSB AND LSB
unsigned long Padc = ( ( Padc_MSB << 8 ) + Padc_LSB ) >> 6 ;
unsigned long Tadc = ( ( Tadc_MSB << 8 ) + Tadc_LSB ) >> 6 ;
float a0 = ( a0_MSB << 5 ) + ( a0_LSB >> 3 ) + ( a0_LSB & 0x07 ) / 8.0 ;
float b1 = ( ( ( ( b1_MSB & 0x1F ) * 0x100 ) + b1_LSB ) / 8192.0) - 3 ;
float b2 = ( ( ( ( b2_MSB - 0x80 ) << 8 ) + b2_LSB ) / 16384.0 ) - 2 ;
float c12 = ( ( ( c12_MSB * 0x100 ) + c12_LSB ) / 16777216.0 ) ;
// CALCULATE PRESSURE
float Pcomp = a0 + ( b1 + c12 * Tadc ) * Padc + b2 * Tadc ;
float PressurekPa = Pcomp * 0.0635 + 50 ;
float PressuremBar = 10 * PressurekPa ;
dtostrf(PressuremBar, 7, 2, pressure);
// Serial.print(pressure); Serial.write(" mBar");Serial.write("\n");
lcd.setCursor(0,2);lcd.print("BARO: ");
if (PressuremBar > 1.0 ) { lcd.print(PressuremBar,1); lcd.print(" hPa "); }
else { lcd.print("NESCIO "); }
}
// /////////////////////////////////////////////////////////////
// Select DSUB K10, SD_3 and SC_3
// TEMPERATURE AND HUMIDITY
void UpDateSensorAtPortK10()
{
digitalWrite(SA, HIGH);
digitalWrite(SB, HIGH);
digitalWrite(A2, LOW);
// TEMPERATURE, MCP8908
Wire.beginTransmission(TemperatureAddress);
Wire.write(0x05);
Wire.endTransmission();
Wire.requestFrom(TemperatureAddress,2);
byte temp_hi = Wire.read();
byte negative = temp_hi & 0x10;
temp_hi = temp_hi & 0x0F ;
byte temp_lo = Wire.read();
int temp = (( temp_hi << 8 ) | temp_lo ) ;
temperature = temp / 16.0 ;
if (negative >= 1) temperature -= 256 ;
lcd.setCursor(0,3);lcd.print("TEMP: ");
if (temperature > -45.0 ) { lcd.print(temperature,1); lcd.print(" ");
lcd.print((char)223); lcd.print("C "); }
else { lcd.print("NESCIO "); }
dtostrf(temperature, 7, 2, tempstring);
// HUMIDITY, CC2D35
Wire.beginTransmission(HumidityAddress);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom(HumidityAddress,2);
int hum_hi = Wire.read();
int hum_lo = Wire.read();
int humi = (( hum_hi << 8 ) | hum_lo ) & 0x3FFF ;
int ok = ( humi & 0xC000 ) >> 14 ;
humidity = humi * 100.0 / 16384 ;
lcd.setCursor(0,1);lcd.print("HUMI: ");
if (humidity > 0 ) { lcd.print(humidity,1); lcd.print(" %RH "); }
else { lcd.print("NESCIO "); }
dtostrf(humidity, 5, 2, HumidityString);
// CALCULATE HEAT INDEX
HeatIndex = temperature ;
if (( temperature >= 26.7 ) && ( humidity >= 40 ))
{
HeatIndex = - 8.784695 + 1.61139411 * temperature + 2.338549 * humidity
- 0.14611605 * temperature * humidity - 0.012308094 * temperature
* temperature - 0.016424828 * humidity * humidity + 0.002211732
* temperature * temperature * humidity + 0.00072546 * temperature
* humidity * humidity - 0.000003582 * temperature * temperature
* humidity * humidity ;
}
dtostrf(HeatIndex, 5, 2, HeatIndexString);
}
// /////////////////////////////////////////////////////////////
// UpDateDewPoint
// DewPointString
// Inspired by : http://www.wetterochs.de/wetter/feuchte.html
void UpDateDewPoint()
{
float a = 0.0 ;
float b = 0.0 ;
if (temperature >= 0) { a = 7.5 ; b = 237.3 ; }
else { a = 7.6 ; b = 240.7 ; }
float SDD = 6.1078 * pow ( 10 , ( ( a * temperature ) / ( b + temperature ) )) ;
float DD = SDD * humidity / 100 ;
float v = log10( DD / 6.1078 );
DewPoint = b * v / (a - v );
dtostrf(DewPoint, 5, 2, DewPointString);
}
// /////////////////////////////////////////////////////////////
// UpDateCloudBase
// CloudBaseString
void UpDateCloudBase()
{
CloudBase = ( temperature - DewPoint ) * 1000 / 4.4 + 535 ;
dtostrf(CloudBase, 7, 1, CloudBaseString);
// SOME OPTIMISATION NEEDED
}
// /////////////////////////////////////////////////////////////
//! Pause :-)
void Pause()
{
delay(100);
}
// /////////////////////////////////////////////////////////////
void loop()
{
// Print Update Response to Serial Monitor
if (client.available())
{
char c = client.read();
Serial.print(c);
}
// Disconnect from ThingSpeak
if (!client.connected() && lastConnected)
{
Serial.println("...disconnected");
Serial.println();
client.stop();
}
// Update ThingSpeak
if(!client.connected() && (millis() - lastConnectionTime
> updateThingSpeakInterval))
{
UpDateSensorAtPortK6();
UpDateSensorAtPortK7();
UpDateSensorAtPortK8();
UpDateSensorAtPortK10();
UpDateDewPoint();
UpDateCloudBase();
updateThingSpeak("field1="+String(tempstring)
+"&field2="+String(lumi, DEC)+"&field3=230.95&field4="
+String(HumidityString)+"&field5="+String(DewPointString)
+"&field6="+String(CloudBaseString)
+"&field7="+String(pressure)+"&field8="+String(HeatIndexString));
}
// Check if Arduino Ethernet needs to be restarted
if (failedCounter > 3 ) {startEthernet();}
lastConnected = client.connected();
}
void updateThingSpeak(String tsData)
{
if (client.connect(thingSpeakAddress, 80))
{
client.print("POST /update HTTP/1.1\n");
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(tsData.length());
client.print("\n\n");
client.print(tsData);
// Serial.println(tsData);
lastConnectionTime = millis();
if (client.connected())
{
Serial.println("Connecting to ThingSpeak...");
Serial.println();
failedCounter = 0;
}
else
{
failedCounter++;
Serial.println("Connection to ThingSpeak failed
("+String(failedCounter, DEC)+")");
Serial.println();
}
}
else
{
failedCounter++;
Serial.println("Connection to ThingSpeak Failed
("+String(failedCounter, DEC)+")");
Serial.println();
lastConnectionTime = millis();
}
}
void startEthernet()
{
client.stop();
Serial.println("Connecting Arduino to network...");
Serial.println();
delay(1000);
// Connect to network amd obtain an IP address using DHCP
if (Ethernet.begin(mac) == 0)
{
Serial.println("DHCP Failed, reset Arduino to try again");
Serial.println();
}
else
{
Serial.println("Arduino connected to network using DHCP");
Serial.println();
}
}
Yes, we know that we mayst have used libraries. The idea was to show all the code which was necessary to achieve the desired function.
✈ Remarks
In case you are 'Flo' : You mayst pick up one sample (fully assembled) free of charge at any time :-)
✈ Share your thoughts
The webmaster does not read these comments regularely. Urgent questions should be send via email.
Ads or links to completely uncorrelated things will be removed.
Your Browser says that you allow tracking. Mayst we suggest that you check that DNT thing ?