|
//-----------------------------------------------------------------------------
// smtp_example.vpl, created 2009-11-11 09:16
//
// An example of how SMTP can be used to monitor a liquid container
//
// Illustration:
//
// |o| <- supply flow monitor
// +-+ <- top valve
// | | | |
// | -| <- High level
// | |
// | -| <- Low level
// +----+ +----+
// +-+ <- bottom valve
// |o| <- drain flow monitor
//
// If any 1-Wire temperature sensors is connected, data will be collected and
// send by email.
//-----------------------------------------------------------------------------
INCLUDE rtcu.inc
VAR_INPUT
level_high : BOOL; | liquid is above high level
level_low : BOOL; | liquid is above low level
flow_supply : INT; | amount of liquid running into tank
flow_drain : INT; | amount of liquid running out of tank
END_VAR;
VAR_OUTPUT
valve_top : BOOL; | active open
valve_bottom : BOOL; | active open
END_VAR;
VAR
// Mail configuration
receiver : STRING := "mail@domain.com";
clock : clockGet; // Reads the builtin Clock
cnv_time : clockLinsecToTime; // Converts number to date format
END_VAR;
//---------------------------------------------------------------------------
// THREAD : tb_SendDataFile
//---------------------------------------------------------------------------
THREAD_BLOCK tb_SendDataFile;
VAR_INPUT
filename : STRING;
END_VAR;
VAR_OUTPUT
status : INT; // mail send status
mail : INT;
END_VAR;
VAR
rc : INT;
END_VAR;
status := 1000;
// Start a new e-mail
mail := smtpNew(Receiver := receiver, Subject := "Data collected.");
// Add text to the e-mail
smtpAddText(Handle := mail, Message := "Data has been collected from ");
cnv_time(linsec := fsFileGetCreateTime(name := filename));
// date
smtpAddText(Handle := mail, Message := intToStr(v := cnv_time.day));
smtpAddText(Handle := mail, Message := "-" + intToStr(v := cnv_time.month));
smtpAddText(Handle := mail, Message := "-" + intToStr(v := cnv_time.year));
// time
smtpAddText(Handle := mail, Message := " " + intToStr(v := cnv_time.hour));
smtpAddText(Handle := mail, Message := ":" + intToStr(v := cnv_time.minute));
smtpAddText(Handle := mail, Message := ":" + intToStr(v := cnv_time.second));
smtpAddText(Handle := mail, Message := " to ");
cnv_time(linsec := clockNow());
// date
smtpAddText(Handle := mail, Message := intToStr(v := cnv_time.day));
smtpAddText(Handle := mail, Message := "-" + intToStr(v := cnv_time.month));
smtpAddText(Handle := mail, Message := "-" + intToStr(v := cnv_time.year));
// time
smtpAddText(Handle := mail, Message := " " + intToStr(v := cnv_time.hour));
smtpAddText(Handle := mail, Message := ":" + intToStr(v := cnv_time.minute));
smtpAddText(Handle := mail, Message := ":" + intToStr(v := cnv_time.second));
// Attach a file to the e-mail
smtpAddAttachment(Handle := mail, Filename := filename);
// Send the e-mail
rc := smtpSendX(Handle := mail);
IF rc <> 0 THEN
DebugFmt(message := "Failed to send data file, error code '\1'.", v1 := rc);
ELSE
// monitor process
REPEAT
status := smtpStatus(Handle := mail);
UNTIL status < 0
END_REPEAT;
DebugMsg(message := "data mail send.");
END_IF;
// Delete file
fsFileDelete(name := filename);
DebugMsg(message := "file '" + filename + "' deleted.");
END_THREAD_BLOCK;
//---------------------------------------------------------------------------
// SendDataMail instant, used by temperature thread.
//---------------------------------------------------------------------------
VAR
SendMail : tb_SendDataFile;
END_VAR;
//---------------------------------------------------------------------------
// THREAD : tb_temperature_monitor
//---------------------------------------------------------------------------
THREAD_BLOCK tb_temperature_monitor;
VAR
next_check : DINT := 0;
fd : FILE;
fname : STRING := "data.csv";
next_send : DINT;
cur_row : DINT := 0;
owCount : INT;
value : DINT;
new_file : BOOL := TRUE;
i : INT;
str : STRING;
END_VAR;
DebugMsg(message:= "Temperature monitor started.");
WHILE TRUE DO
// Create new data file, on new collection.
IF new_file THEN
new_file := FALSE;
// Delete any old file
fsFileDelete(name := fname);
// Create file
fd :=fsFileCreate(name := fname);
// Write header row followed by a new line to file
fsFileWriteStringNL(fd := fd, str := "$"Time$";$"Average$";$"Values ->$"");
next_send := clockNow() + 300; // send each 5th minute
cur_row := 2;
END_IF;
// Collect data
IF next_check < clockNow() THEN
next_check := clockNow() + 10; // monitor each 10 second.
// Search for One-Wire devices
owCount := owSearch(family := 1);
// get system clock
clock();
// write check time in first column
fsFileWriteString(fd := fd, str := "$"" + intToStr(v := clock.day));
fsFileWriteString(fd := fd, str := "-" + intToStr(v := clock.month));
fsFileWriteString(fd := fd, str := "-" + intToStr(v := clock.year));
fsFileWriteString(fd := fd, str := " " + intToStr(v := clock.hour));
fsFileWriteString(fd := fd, str := ":" + intToStr(v := clock.minute));
fsFileWriteString(fd := fd, str := ":" + intToStr(v := clock.second) + "$"");
// generate average cell recognized by Microsoft Excel and OpenOffice Calc
str := strFormat(format := ";$"=SUM(C\4:O\4)/\1$"", v1 := owCount, v4 := cur_row);
// write sum function
fsFileWriteString(fd := fd, str := str);
// Write found temperatures
FOR i := 1 TO owCount DO
value := owTempGet(device := SINT(i));
// write data to file
fsFileWriteString(fd := fd, str := ";$"");
fsFileWriteString(fd := fd, str := dintToStr(v := value / 100));
fsFileWriteString(fd := fd, str := ",");
fsFileWriteString(fd := fd, str := dintToStr(v := value MOD 100));
fsFileWriteString(fd := fd, str := "$"");
END_FOR;
// Write newline
fsFileWriteString(fd := fd, str := "$N");
cur_row := cur_row + 1;
// wait 5 second before next check
Sleep(delay := 5000);
END_IF;
// Time to send data
IF next_send < clockNow() THEN
fsFileClose(fd := fd);
IF SendMail._running THEN
DebugMsg(message := "Waiting for last mail to finish.");
WHILE SendMail.status >= 0 AND SendMail._running DO
DebugFmt(message := "Progress : \1", v1 := SendMail.status);
Sleep(delay := 500);
END_WHILE;
END_IF;
// Rename file
fsFileRename(name_old := fname, name_new := "temp.csv");
// send the file as an attachment
SendMail(filename := "temp.csv");
new_file := TRUE;
END_IF;
END_WHILE;
END_THREAD_BLOCK;
//---------------------------------------------------------------------------
// THREAD_BLOCK : tb_level_monitor
//---------------------------------------------------------------------------
THREAD_BLOCK tb_level_monitor;
VAR
trig_supply : RF_TRIG;
trig_drain : RF_TRIG;
trig_high : RF_TRIG;
trig_low : RF_TRIG;
message : STRING;
subject : STRING;
send_msg : BOOL;
rc : INT;
END_VAR;
DebugMsg(message := "Level monitor started.");
// open vales according to current state
IF NOT level_high THEN
valve_top := ON;
END_IF;
IF level_low THEN
valve_bottom := ON;
END_IF;
// skip initial level warnings
trig_high(trig := level_high);
trig_low(trig := level_low);
trig_drain(trig := flow_drain > 10);
trig_supply(trig := flow_supply > 10);
WHILE TRUE DO
send_msg := FALSE;
trig_high(trig := level_high);
trig_low(trig := level_low);
trig_drain(trig := flow_drain > 10);
trig_supply(trig := flow_supply > 10);
// check high level
IF trig_high.rq THEN
subject := "WARNING: Liquid level critical high";
message := subject + ", closing top valve.";
valve_top := OFF;
send_msg := TRUE;
ELSIF trig_high.fq THEN
subject := "NOTIFY: Liquid level below critical high";
message := subject + ", opening top valve.";
valve_top := ON;
send_msg := TRUE;
END_IF;
// check low level
IF trig_low.fq THEN
subject := "WARNING: Liquid level critical low";
message := subject + ", closing bottom valve.";
valve_bottom := OFF;
send_msg := TRUE;
ELSIF trig_low.rq THEN
subject := "NOTIFY: Liquid level above critical low";
message := subject + ", opening bottom valve.";
valve_bottom := ON;
send_msg := TRUE;
END_IF;
IF send_msg THEN
DebugMsg(message := message);
// Send an e-mail
rc := smtpSend(Receiver := receiver, Subject := subject, Message := message);
IF rc <> 0 THEN
DebugFmt(message := "Failed to send message, error code '\1'.", v1 := rc);
END_IF;
END_IF;
// monitor supply and drain pipes
IF trig_supply.fq AND valve_top THEN
subject := "WARNING: supply pipe clogged";
message := subject + ", no action taken.";
DebugMsg(message := message);
// Send an e-mail
rc := smtpSend(Receiver := receiver, Subject := subject, Message := message);
IF rc <> 0 THEN
DebugFmt(message := "Failed to send message, error code '\1'.", v1 := rc);
END_IF;
END_IF;
IF trig_drain.fq AND valve_bottom THEN
subject := "WARNING: drain pipe clogged";
message := subject + ", no action taken.";
DebugMsg(message := message);
// Send an e-mail
rc := smtpSend(Receiver := receiver, Subject := subject, Message := message);
IF rc <> 0 THEN
DebugFmt(message := "Failed to send message, error code '\1'.", v1 := rc);
END_IF;
END_IF;
// wait 2 seconds before next scan
Sleep(delay := 2000);
END_WHILE;
END_THREAD_BLOCK;
//---------------------------------------------------------------------------
// PROGRAM: smtp_example
//---------------------------------------------------------------------------
PROGRAM smtp_example;
VAR
rc : INT;
last_signal_time : DINT := 0;
temp_monitor : tb_temperature_monitor;
level_monitor : tb_level_monitor;
END_VAR;
DebugMsg(message := "Initializing.");
// Open media
rc := fsMediaOpen(media := 0);
DebugFmt(message := "fsMediaOpen = \1", v1 := rc);
// Controls power to the Cellular module
rc := gsmPower(power := ON);
DebugFmt(message := "gsmPower = \1", v1 := rc);
// Open/activate Cellular network connection.
rc := netOpen(iface:=_NET_IFACE_CELLULAR);
DebugFmt(message := "netOpen = \1", v1 := rc);
// Set SMTP configuration
smtpSetConfig(
IP :="mail.domain.com",
Port := 25,
Sender := "tank_monitor@domain.com",
Authenticate := OFF
);
// Open the smtp interface
rc := smtpOpen();
DebugFmt(message := "smtpOpen = \1", v1 := rc);
DebugMsg(message := "Starting threads.");
temp_monitor();
level_monitor();
DebugMsg(message := "Ready");
BEGIN
IF last_signal_time < clockNow() THEN
last_signal_time := clockNow() + 10; // check again in 10sec
// Check if Cellular network connection is established
IF NOT netConnected(iface:=_NET_IFACE_CELLULAR) THEN
DebugMsg(message := "WARNING: no connection to Cellular network, sending mails not posible.");
END_IF;
IF NOT temp_monitor._running THEN
DebugMsg(message := "ERROR: Temperature monitor not running, starting.");
temp_monitor();
END_IF;
IF NOT level_monitor._running THEN
DebugMsg(message := "ERROR: Level monitor not running, starting.");
level_monitor();
END_IF;
END_IF;
END;
END_PROGRAM;
|