/*
Forschungsschiff "Polarfuchs"
N. Cueppers
www.nicnet.de/wordpress
Stellt Wetterdaten über einen Browser zur Verfuegung:
Wassertemperatur mittels Thermistor
Himmel mittels Photodiode
Regen mittels Spannungsabfall
Ausserdem ueberwacht Polarfuchs sich selbst auf Lecks (Wassereinbruch aka Bilgenalarm) mittels Spannungsabfall
und gibt auf der Webseite Auskunft über seine Betriebsspannung.
Ist der Wert kritisch, sendet Polarfuchs das Notsignal SOS per Toplicht (LED) und Horn (Buzzer).
Bei Dunkelheit schaltet Polarfuchs das Toplicht ein. Da es keinen eigenen Atrieb hat, genuegt dafuer tatsaechlich ein weisses Rundumlicht.
(§ 3.13 Abs. 5 BinSchStrO)
Der Name ist angelehnt an das kleinste mir bekannte deutsche Forschungsschiff: http://www.deutsche-meeresforschung.de/de/polarfuchs
*/
#define SSID "SSID"
#define PASSWORD "PASSWORD"
#define LED_WLAN 13
#define DEBUG true
//Pins I/O
#define THERMO A0
#define PHOTO A1
#define vRegen_pin 4
#define vBilge_pin 5
#define LED 9
#define buzzer 8
#include <SoftwareSerial.h>
SoftwareSerial esp8266(11, 12); // RX, TX
const byte site[] PROGMEM = {
60,72,84,77,76,62,60,72,69,65,68,62,13,10,60,108,105,110,107,32,114,101,108,61,34,105,99,111,110,34,32,104,114,101,102,61,34,100,97,116,97,58,59,98,97,115,101,54,52,44,105,86,66,79,82,119,48,75,71,103,111,61,34,62,13,10,60,109,101,116,97,32,110,97,109,101,61,34,118,105,101,119,112,111,114,116,34,32,99,111,110,116,101,110,116,61,34,119,105,100,116,104,61,100,101,118,105,99,101,45,119,105,100,116,104,44,32,105,110,105,116,105,97,108,45,115,99,97,108,101,61,50,46,48,44,32,117,115,101,114,45,115,99,97,108,97,98,108,101,61,121,101,115,34,62,13,10,60,109,101,116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,114,101,102,114,101,115,104,34,32,99,111,110,116,101,110,116,61,34,51,34,62,13,10,60,116,105,116,108,101,62,13,10,80,111,108,97,114,102,117,99,104,115,13,10,60,47,116,105,116,108,101,62,13,10,60,47,72,69,65,68,62,13,10,60,66,79,68,89,32,98,103,99,111,108,111,114,61,34,35,70,70,70,70,70,70,34,32,116,101,120,116,61,34,35,48,48,48,48,48,48,34,62,13,10,60,70,79,78,84,32,115,105,122,101,61,34,51,34,32,70,65,67,69,61,34,86,101,114,100,97,110,97,34,62,13,10,60,98,62,80,79,76,65,82,70,85,67,72,83,60,47,98,62,13,10,60,47,70,79,78,84,62,13,10,60,70,79,78,84,32,115,105,122,101,61,34,50,34,32,70,65,67,69,61,34,86,101,114,100,97,110,97,34,62,13,10,60,66,82,62,13,10,42,98,114,105,103,104,116,42,13,10,60,47,102,111,110,116,62,13,10,60,47,72,84,77,76,62,13,10
};
void setup() {
pinMode(vRegen_pin, INPUT);
digitalWrite(vRegen_pin, HIGH);
pinMode(vBilge_pin, INPUT);
digitalWrite(vBilge_pin, HIGH);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
pinMode(buzzer, OUTPUT);
digitalWrite(buzzer, LOW);
Serial.begin(19200);
esp8266.begin(19200);
if (!espConfig()) serialDebug();
else digitalWrite(LED_WLAN, HIGH);
if (configTCPServer()) debug("Server Aktiv"); else debug("Server Error");
}
void loop() {
if (analogRead(PHOTO) > 100)
digitalWrite(LED, LOW);
else digitalWrite(LED, HIGH);
int bilge=analogRead(A4);
if ((bilge < 800) || (readVcc() < 4200 )) //Achtung, EasterEgg: Mit wenigen weiteren Widerständen könnte man über Spannungsteiler SINNVOLL die Batteriespannung überwachen. Dann gibt es auch ein Notsignal, wenn die Spannung zu niedrig wird!
{
digitalWrite(LED, LOW);
delay(600); did(); did(); did(); da(); da(); da(); did(); did(); did(); delay(600);
}
String xBuffer;
if (esp8266.available()) // check if the esp is sending a message
{
if (esp8266.find("+IPD,"))
{
debug("Incomming Request");
int connectionId = esp8266.parseInt();
if (sendWebsite(connectionId, createWebsite())) debug("Website send OK"); else debug("Website send Error");
}
}
}
boolean sendWebsite(int connectionId, String webpage)
{
boolean succes = true;
if (sendCom("AT+CIPSEND=" + String(connectionId) + "," + String(webpage.length()), ">"))
{
esp8266.print(webpage);
esp8266.find("SEND OK");
succes &= sendCom("AT+CIPCLOSE=" + String(connectionId), "OK");
}
else
{
succes = false;
}
return succes;
}
String createWebsite()
{
String xBuffer;
double vTemp = Thermistor(analogRead(THERMO));
String br = "<br>";
int vcc = readVcc();
String stringOne = "<br><b>Wetterdaten:</b><p> ";
int webregen = analogRead(A5);
String esregnet;
if (webregen > 900)
esregnet = "trocken";
else esregnet ="Regen";
int licht = analogRead(PHOTO);
String webhimmel;
if (licht >= 100 & licht <= 700)
webhimmel = "bedeckt";
else if (licht > 700) webhimmel = "sonnig";
else webhimmel ="Nacht";
int bilgenwasser = analogRead(A4);
String webbilge;
if (bilgenwasser > 900)
webbilge = "trocken";
else webbilge ="Wassereinruch";
String stringThree = stringOne + vTemp + " Grad " + br + webhimmel + br + esregnet + br + "<p><b>Schiffsstatus</b>"+ br + br + "Bordspannung: " + vcc + " mV" + br + "Bilge: " + webbilge;
for (int i = 0; i <= sizeof(site); i++)
{
char myChar = pgm_read_byte_near(site + i);
xBuffer += myChar;
}
xBuffer.replace("*bright*", stringThree);
return xBuffer;
}
//-----------------------------------------Config ESP8266------------------------------------
boolean espConfig()
{
boolean succes = true;
esp8266.setTimeout(5000);
succes &= sendCom("AT+RST", "ready");
esp8266.setTimeout(1000);
if (configStation(SSID, PASSWORD)) {
succes &= true;
debug("WLAN Connected");
debug("My IP is:");
debug(sendCom("AT+CIFSR"));
}
else
{
succes &= false;
}
//shorter Timeout for faster wrong UPD-Comands handling
succes &= sendCom("AT+CIPMODE=0", "OK");
succes &= sendCom("AT+CIPMUX=0", "OK");
return succes;
}
boolean configTCPServer()
{
boolean succes = true;
succes &= (sendCom("AT+CIPMUX=1", "OK"));
succes &= (sendCom("AT+CIPSERVER=1,80", "OK"));
return succes;
}
boolean configTCPClient()
{
boolean succes = true;
succes &= (sendCom("AT+CIPMUX=0", "OK"));
//succes &= (sendCom("AT+CIPSERVER=1,80", "OK"));
return succes;
}
boolean configStation(String vSSID, String vPASSWORT)
{
boolean succes = true;
succes &= (sendCom("AT+CWMODE=1", "OK"));
esp8266.setTimeout(20000);
succes &= (sendCom("AT+CWJAP=\"" + String(vSSID) + "\",\"" + String(vPASSWORT) + "\"", "OK"));
esp8266.setTimeout(1000);
return succes;
}
boolean configAP()
{
boolean succes = true;
succes &= (sendCom("AT+CWMODE=2", "OK"));
succes &= (sendCom("AT+CWSAP=\"NanoESP\",\"\",5,0", "OK"));
return succes;
}
boolean configUDP()
{
boolean succes = true;
succes &= (sendCom("AT+CIPMODE=0", "OK"));
succes &= (sendCom("AT+CIPMUX=0", "OK"));
succes &= sendCom("AT+CIPSTART=\"UDP\",\"192.168.255.255\",90,91,2", "OK"); //Importand Boradcast...Reconnect IP
return succes;
}
//-----------------------------------------------Controll ESP-----------------------------------------------------
boolean sendUDP(String Msg)
{
boolean succes = true;
succes &= sendCom("AT+CIPSEND=" + String(Msg.length() + 2), ">"); //+",\"192.168.4.2\",90", ">");
if (succes)
{
succes &= sendCom(Msg, "OK");
}
return succes;
}
boolean sendCom(String command, char respond[])
{
esp8266.println(command);
if (esp8266.findUntil(respond, "ERROR"))
{
return true;
}
else
{
debug("ESP SEND ERROR: " + command);
return false;
}
}
String sendCom(String command)
{
esp8266.println(command);
return esp8266.readString();
}
//-------------------------------------------------Debug Functions------------------------------------------------------
void serialDebug() {
while (true)
{
if (esp8266.available())
Serial.write(esp8266.read());
if (Serial.available())
esp8266.write(Serial.read());
}
}
void debug(String Msg)
{
if (DEBUG)
{
Serial.println(Msg);
}
}
//Spannungsmessung gefunden auf
//https://code.google.com/p/tinkerit/wiki/SecretVoltmeter
long readVcc() {
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(5); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result; // Back-calculate AVcc in mV
return result;
}
//EasterEgg2: Interne Temperatur des Boards könnte man auch noch ausgeben! :)
long readTemp() {
// Read temperature sensor against 1.1V reference
#if defined(__AVR_ATmega32U4__)
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0);
ADCSRB = _BV(MUX5); // the MUX5 bit is in the ADCSRB register
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(REFS1) | _BV(MUX5) | _BV(MUX1);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0);
#else
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
#endif
delay(5); // Wait for ADMUX setting to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA,ADSC)); // measuring
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both
long result = (high << 8) | low; // combine the two
return result;
}
double Thermistor(int RawADC) {
//Source: http://playground.arduino.cc/ComponentLib/Thermistor2
double Temp;
Temp = log(10000.0 * ((1024.0 / RawADC - 1)));
// =log(10000.0/(1024.0/RawADC-1)) // for pull-up configuration
Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp )) * Temp );
Temp = Temp - 273.15; // Convert Kelvin to Celcius
// Temp = (Temp * 9.0)/ 4.7 + 32.0; // Convert Celcius to Fahrenheit
return Temp;
}
void did() {
tone(buzzer, 440, 100);
digitalWrite(LED, HIGH);
delay(200);
noTone(buzzer);
digitalWrite(LED, LOW);
delay(200);
}
void da() {
tone(buzzer, 440, 600);
digitalWrite(LED, HIGH);
delay(600);
noTone(buzzer);
digitalWrite(LED, LOW);
delay(200);
}