Introduction: Get Public IP Change Notification With RPi and Node.JS
With a Raspberry PI at home and a real need to, sometimes, access it remotely, whether by ssh or any other service I wanted a simple way to always have by hand my home dynamic public IP address. Also a requirement, no need to subscribe a third party service for that. Having some knowledge in Node.js, I started looking into it. Later I found that my IP doesn't change so often as I supposed... Good, i don't feel bad for having opt for e-mail notifications! :)
Step 1: Requirements
- A RaspberryPI (any version) or any other computer (Linux), and physical access to it or accessible by "ssh".
- Node.js Installed (I won't talk about that, because there's lots of tutorials on the internet and that's not the point of this instructable)
- A router connected to the internet (so that you have a public IP)
- Access to a SMTP Mail Server. Not hard if you have an ISP account.
Step 2: Preparation
Whether directly or remotely by ssh, you should open a terminal window on your RPI and gain access to the command line.
- DIG:
'dig' is a linux command you can use to query DNS name servers on some tasks. For this project dig is the "magic" that obtains the public IP. Is part of a package that you can install with the following command :
> sudo apt-get install dnsutils
After installing you can test it issuing the following command at command prompt. (Later it will be used in our NodeJS app):
> dig +short myip.opendns.com @resolver1.opendns.com
If all went good, this should return your public ip
- NODEMAILER
I've chosen mail to receive the change notifications. For that I used an easy to use Node module available at :
https://github.com/nodemailer/nodemailer
To install it just go to the terminal window and type (if you're not root, precede it with 'sudo'):
> npm install nodemailer ... > npm install nodemailer-smtp-transport
The second command installs a second Node.js module needed to create a SMTP transport for the nodemailer.
Step 3: The Node.js Application (config.js)
First I created a config file (config.js) with the following content:
module.exports = { // number of minutes between calls to get the public IP getServerInterval: function(){ return 180; }, // SMTP server options getServerOptions: function(){ return { host : 'smtp.your_isp.com', port : 465, secure : true, ignoreTLS : true, debug : true, auth: { user : 'youra_account@your_isp.com', pass : 'your_password' } } }, getMailOptions: function(){ return { from: '????@????.com', to: '????@???.com', // the email address where you want to receive the notification // the next parameters can be specified later subject: 'IP has changed', text: 'Hello world', html: '<strong>Hello world</strong>' // html body } } }
The main application will import this config file in the following lines:
var intervalMinutes = require('./config.js').getServerInterval();
var serverOptions = require('./config.js').getServerOptions();
var mailOptions = require('./config.js').getMailOptions();
Step 4: The Node.js Application (app.js)
The main application file will be:
Start by the requires (nodemailer, nodemailer-smtp-transport, fs and the already made config.js )
// Variable declaration and requires
var exec = require('child_process').exec;
var nodeMailer = require('nodemailer');var smtpTransport = require('nodemailer-smtp-transport');
var serverOptions = require('./config.js').getServerOptions();
var mailOptions = require('./config.js').getMailOptions();
var intervalMinutes = require('./config.js').getServerInterval();
var fs = require('fs');
var sendServer = nodeMailer.createTransport(smtpTransport(serverOptions));
var logStream = fs.createWriteStream("log.txt", {'flags': 'a'});
var lastIP = "";
// The function responsible for sending the mail
var sendMail = function(ipAddress){ var msg= "---------------------------\n";
msg += "SendMail : " + ipAddress ;
mailOptions.text = ipAddress
mailOptions.html = "" + ipAddress + "";
sendServer.sendMail(mailOptions, function(error, info){
if (error){
msg += "Err : " + error;
logStream.write(" SendMail.Err : " + error);
console.log(error);
}else{
console.log('Message sent: ' + info.response); msg += info.response ;
}
msg += "\n---------------------------\n";
logStream.write(msg);
})
};
// Getting the external IP address
var getExternalIp = function(errorCallback,successCallback){
var child = exec("dig +short myip.opendns.com @resolver1.opendns.com", function (error, stdout, stderr) {
if (error !== null) {
errorCallback(error);
}else{
var dt = new Date();
var dtSt = dt.getFullYear() + '-' + ("0" + (dt.getMonth() + 1)).slice(-2) + '-' + ("0" + (dt.getDate() + 1)).slice(-2) + ' ' + ("0" + dt.getHours()).slice(-2) + ':' + ("0" + dt.getMinutes()).slice(-2) + ':' + ("0" + dt.getSeconds()).slice(-2)
logStream.write(dt + " : " + stdout) ;
if (stdout != lastIP){
var lastStream = fs.createWriteStream("last.txt");
lastStream.write(stdout);
lastIP = stdout
successCallback(stdout);
}
}
});
}
// Error callback to be called on next two
var errorFunction = function(err){
logStream.write("ERR : " + err);}
// Main Timer to poll IP and send email if it changed
function startTimer(){
setInterval(function(){getExternalIp(errorFunction, sendMail);
}, 60000 * intervalMinutes);
}
// Each launch of the application, reads the last obtained IP from a manual created file (last.txt)
fs.readFile('./last.txt', 'utf8' , function(err, data){
if (err) throw err;else{
var dt = new Date();
var dtSt = dt.getFullYear() + '-' + ("0" + (dt.getMonth() + 1)).slice(-2) + '-' + ("0" + (dt.getDate() )).slice(-2) + ' ' + ("0" + dt.getHours()).slice(-2) + ':' + ("0" + dt.getMinutes()).slice(-2) + ':' + ("0" + dt.getSeconds()).slice(-2)
lastIP = data;
logStream.write("\n");
logStream.write("\n");
logStream.write("*****************************************\n");
logStream.write(dtSt) ;
logStream.write("\n");
console.log("startServer:lastIP : " + lastIP);
logStream.write("START_SERVER : lastIP : " + lastIP + "\n");
getExternalIp(errorFunction, sendMail);
setTimeout(startTimer, 10000);
}
})
Step 5: Running It
In order to test it, issue:
$ node app.js
Watch the log.txt and the last.txt files.
If you want (I think you should) have it persistently running, no matter what happens (reboots, ...)
see my other Instructable:
Node.js app as a RPI Service (boot at startup)
Cheers...