PICAXE/Perl Project A Dead-Man Alert SystemPICAXE and Perl join forces to send an email alert (via gmail) if there's a man down at home. Max Carter
|
Regulator Components Installed![]() |
LED and Resistor Installed![]() |
The white stuff is RTV silicone.
(The receive end of the remote monitor link.)
Another RFD21733 is used to receive the signal from the monitor transmitter, in this case configured for "Mode 5" (see RFD21733 data sheet). In this configuration, the transceiver outputs a 500mS positive-going pulse every 2 seconds as long as a valid signal is being received from the far end of the link. When the signal stops, the output stays low.
A couple of PICAXE 08M chips are used to detect receiver activity and convey it to the computer. 08M number one (#1) acts as a integrating timer and latch. The timer detects the presence of pulses from the receiver (RFD21733). "Activity" is reported only when a complete on/off cycle of the monitored appliance (the light) occurs. Thus, if the light is accidentally left on, the timer's output latch will not be set until such time as it is turned off. A light left on or off will eventually be reported as "No Activity". The second 08M (#2), when polled by the computer, reports the state of the timer's output latch and issues a pulse to reset the latch for the next occurrence. The idea here is not to count the times the light is switched on and off, but to report when it has not occurred within the sample interval.
And what if the power fails? Under certain conditions - the bathroom light left on, for example - a power failure and subsequent restoral might be misinterpreted as "normal activity". That it is not misinterpreted is based on the fact that power failures are not local. If the power fails in the bathroom, it also fails in the computer room. If the interface notices that power has failed, it ignores input from the remote and locks up in whatever state it happens to be in at the time. When power is restored, the interface resumes normal operation in its before-failure state (unless it happens to have been reset by the computer - the interface retains its ability to talk to the computer through a power failure).
Figure 2
The thick wire on pins 9 and 10 serves as a counterpoise to the antenna. It improves antenna efficiency.
The gray connector is a female DE9; it plugs into the computer's serial port. The red/black wire provides protected 5 volts DC; it plugs into one of the computer's power supply connectors. The USB connector plugs into an unprotected 5-volt power source. This could be a USB charger (as in Figure 1), but in this case it's connected to a USB port on another computer, not power-protected, next to the server. (The USB ports on computers are hot whenever they're plugged into a hot outlet and go dead when the outlet goes dead, regardless of whether or not the computer is running.)
Connection to Serial Port![]() |
Power Connection![]() |
See also: Scheduling the Polling Interval starting below 'Firmware/Software'. ↓
Three programs are shown below, two for the 08M chips (in PICAXE Basic), and one for the Perl script that runs on the computer.
Copy the following code to the PICAXE Programming Editor and program the chip (works also on 08M2 chip):
'initializes on power up, pause 100 '100mS low 0 'sets remote signal LED (pin 7) to "not present" low 1 'sets activity (pin 6) to "no activity" b0 = 50 'sets accumulator count to 50 b1 = 0 'sets accumulator output to 0 b2 = 0 'sets cycle delay memory to 0 power_check: if pin3 = 1 then 'IF input 3 (pin 4) high, (this comes from PIC#2) low 1 ' resets output latch, (pin 6) low endif if pin2 = 1 then 'if input 2 (pin 5) high (high here indicates power OK) goto execute else pause 100 goto power_check endif execute: pause 100 'milliseconds, establishes sample rate at about 10 per second ReadADC10 4, W5 'reads voltage on input 4 (pin 3) from the RFD21733 receiver if W5 < 340 then 'less than about 1.65 volts, (half of 3.3 volts) b0 = b0 - 1 'discharges accumulator (b0), approx 20 second discharge (4 seconds on powerup) else b0 = b0 + 10 'charges accumulator; charge rate 10 times faster than discharge rate endif if b0 > 240 then 'limits max value b0 to 240 b0 = 240 endif if b0 < 10 then 'limits min value b0 to 10 b0 = 10 endif if b0 > 60 then 'accumulator output toggles high b1 = 1 high 0 'remote signal present, (pin 7) elseif b0 < 40 then 'accumulator output toggles low b1 = 0 low 0 'remote signal not present (pin 7) endif if b2 > b1 then 'this comparison looks for a 1 to 0 transition ("activity") high 1 'sets output latch ("activity detected") (pin 6) endif b2 = b1 'shifts contents of b1 to b2, retains the state of b1 for comparison in the next cycle goto power_check 'restarts check/sample/accumulate cycle
Copy the following code to the PICAXE Programming Editor and program the chip (works also on 08M2 chip):
main: serin 3, N2400, ("c="), b0 'waits here for input from computer, gets character after qualifier ("c=") if b0 = "d" then 'looks for "d" high 4 '(pin 3) lights "polling" LED if pin1 = 1 then 'gets input from latch, on pin 6 serout 0, N2400, ("1", 13) 'sends ASCII chr "1" to computer; 13 is CR, high 2 'sets output 2 high, resets latch in PIC #1 pause 200 '200ms low 2 'sets output 2 low else serout 0, N2400, ("0", 13) 'sends ASCII "0" to computer; 13 is CR endif pause 300 low 4 'extinguishes 'poll' LED endif goto main
Requires late-model ActivePerl installation
[Community Edition (free), here]
And modules:
|
Copy the following code to your favorite text editor; edit the email message header (From:, To:, Cc:, Subject:) and body ($senddata) as appropriate; add your gmail account information (address and password*), recipient addresses, and the path (c:/folder/etc) to the /time_ref.txt file (use forward slashes). Save the file (with .pl extension, eg, "monitor_dad.pl") to a location on the computer:
use strict; use warnings; my $time = time; #gets current time (computer time in seconds) my $stoptime = $time + 2; #adds 2 seconds my @recipients; #list of email recipients my $subject; #subject line of the email my $senddata; #this will be the email message body my $status; #status (1/0) of PICAXE interface latch use Win32::SerialPort; my $Sport = Win32::SerialPort->new('COM4'); #this creates an object, named $Sport, #that provides a connection to COM4 #make this any available COM port you like $Sport->baudrate(2400); #configures serial port $Sport->parity('none'); $Sport->databits(8); $Sport->stopbits(1); $Sport->handshake('none'); $Sport->write_settings; sub get_status($) { #subroutine gets status of monitor interface latch (PICAXE #1) $Sport->write("c=d"); #sends command to interface, "c=" is qualifier, "d" is command $_ = ''; #clears (sets to 'nothing') do { #this will stop the program if it does not hear back from the interface within 2 seconds $time = time; #gets computer time if ($time >= $stoptime) { #if current time greater than or equal to stoptime, die "no response from interface"; } $_ .= $Sport->read(1); #reads serial port chr, ".=" means concatinate } while (!/\r/); #until carriage return (\r) received return $_; #ends do-while loop, returns value } $_ = get_status (""); #calls the get_status subroutine above $_ =~ (s/\r//); #gets rid of the CR - substitutes '\r' with ''(nothing) $status = $_; undef $Sport; #destroys serial port object if ($status != 1) { #if not "1", ie, if latch not set no_activity(); #calls no_activity sub } else { normal_activity(); #calls normal_activity sub } sub no_activity { #sends "no activity" email @recipients = ("intendedrecipient\@whatever.com","somebodyelse\@wherever.com"); #address of #'intended recipient'and 'somebody else', 'somebody else' optional, #any number can be added, separate addresses with commas, must be valad addresses #note added backslash "\" before "@" must be present (very important) $subject = "Dad: NO ACTIVITY :("; #or whatever you want here $senddata = "NO ACTIVITY RECORDED LAST 12 HOURS! Check on dad! :("; #email message body #your message here send_email(); #calls send_email sub } sub rpt_interval_start { #get reporting interval start time (from time_ref.txt file) open (my $fh, "<", "path/time_ref.txt"); #$fh is "file handle", opens for read while (<$fh>) { #reads interval start time, "<>" means readline until \r return $_; } close $fh; } sub normal_activity { $_ = rpt_interval_start(); #gets interval start time from rpt_interval_start sub above if ($time > ($_ + 600000)) { #if one week has passed (1 week = 604800 seconds) sends "normal activity" email @recipients = ("intendedrecipient\@whatever.com","somebodyelse\@wherever.com"); #address of 'intended recipient' and 'somebody else' (as many as you like) #(may be differerent from @recipients in no_activity sub above) #somebody elses optional, separate addresses with commas, #must be valid addresses #note backslashes "\" before "@" (very important) $subject = "Dad: Normal activity"; #or whatever $senddata = "Normal activity noted, last 7 days. :)"; #email message body send_email(); #calls email sub, "()" needed to keep 'strict' above happy } } sub send_email { use Net::SMTP; my $smtp = Net::SMTP->new('smtp.gmail.com', SSL => 1, Debug => 1); #Googlemail requires SSL $smtp->auth('youremailaddress@gmail.com', 'app password'); #Gmail requires authorization #you must have a gmail account, #The account holder must create a 16-digit 'app password' #see: https://support.google.com/accounts/answer/185833?hl=en $smtp->mail('youremailaddress@gmail.com'); $smtp->recipient(@recipients); $smtp->data(); $smtp->datasend('From: You '."\n"); $smtp->datasend('To: Recipient Name'."\n"); $smtp->datasend('Cc: Somebody Else'."\n"); $smtp->datasend("Subject: $subject\n"); $smtp->datasend("\n"); #end of header $smtp->datasend("$senddata\n"); $smtp->datasend(""); $smtp->dataend(); $smtp->quit; write_current_time(); #calls write_current_time sub } sub write_current_time { #writes current time (interval start time) to time_ref.txt file, #starts new reporting interval open (my $fh, '>', 'path/time_ref.txt'); #opens file for write (overwrite) print $fh "$time\r"; #writes current time to file close $fh; }
This is done with "Scheduled Tasks" on older PCs (XP, etc) or "Task Scheduler" on later models, usually under "accessories" somewhere in the start menu. "Task" is set to the location of the Perl script on the computer (path\filename.pl); "start time" is set to midnight on some day convenient for the recipient (say, Friday); "repeat task" is set to the desired polling interval (12 hours, etc). Keep in mind that the "polling interval" is the time between polls of the interface. The "reporting interval" is the time between transmissions of the normal activity email.* If any polling interval passes with no activity, the program does not wait for the reporting inverval. The no activity email is immediately sent.
*The reporting interval can be changed by editing the line "if ($time > ($_ + 600000)) {" (1 week = 604800 seconds).
RFD21733 - |
The RF module used in this project has been discontinued by the manufacturer but old stocks are still available from suppliers. Google search "RFD21733" and/or variants "RFD21735" (external ant.) and "RFD21813" (DIP) and "RFD21743" (radio in ant.). eBay is always a good place to look: eBay |
PICAXE 08M2 - | Sparkfun PICAXE.com |
Schematics produced with DCCAD.
Here he is checkin' the prints..