Can my agent find the IP address of my imp?

I want my imp to display the time corrected for local time and daylight savings, using an internet API call. The services I can find need either the GPS coordinates or the IP address to locate the timezone. I cannot find in the imp API any way to access the IP address of my device, and I don’t want to add a GPS receiver just to detect daylight savings! I also don’t want to do the calculation based on dates in March and November as in another discussion, because that is not valid everywhere and might change.

Can anybody help me find this IP address? Of course I don’t want the local address, but the public IP of my router. If this is not exposed in the API then might it be in future?

By the way I note that the server logs are stamped with a different time from the UTC that I get from my time() or date() on either device or agent. This happens to be my local time in the UK, but I suppose that is just coincidence. Does anybody know what time zone is used on the server logs?

I don’t see anywhere in the API that the IP address of the imp is exposed. But there is a workaround to discover your router’s IP address in the Agent.

Create an http handler, and pass a specific query value to the Agent handler letting the agent know you want to set the IP address. Do this from a computer connected to the same router.

https://agent.electricimp.com/yourkeyhere?SetRouterIP=1

In your http.handler in the agent, you can read the IP address of the caller and send it down to the imp, or use it to query the timezone for the IP address using a web service, and then pass the timezone offset down to the imp. Save this value in permanent storage on the agent, and you can pass it down to the Imp whenever it connects so that setting the IP address is a one time deal, and you can determine the timezone automatically thereafter, on whatever schedule you need.
In this code example, the http handler checks for a SetRouterIP query parameter. If it exists, the IP address of the caller is retrieved and persisted, and the IP address is passed to the Imp. Every time the imp re-connects to the agent, the IP address is pulled from server side storage and sent down to the imp. You can modify this to send the timezone down to the imp instead.

`
settings <- server.load();

http.onrequest(function(request,res){

if (“SetRouterIP” in request.query) {
device.send(“SetRouterIP”, request.headers[“x-forwarded-for”]);
server.save( {RouterIP= request.headers[“x-forwarded-for”]});
res.send(200,“Set the router IP address to:” + request.headers[“x-forwarded-for”]);
}
});

// Whenever the imp connects, send it the IP address (or timezone if you have it)
device.onconnect(function() {
if( “RouterIP” in settings ) {
device.send(“SetRouterIP”, settings.RouterIP );
server.log(“Device Connected. Set the router IP address to:” + settings.RouterIP );
}
else
server.log(“IP address not set”);
});

`

Now on the device side, all you need is something to receive the IP address from the agent, or you can pass the timezone (more likely) after you have used the web query on the agent to find it from the IP address.

`
myIP <- “empty”;

agent.on(“SetRouterIP”, function( data ) {

myIP = data;
server.log("My IP " + myIP );

});

`

So, a one time “configuration” and then it will happen automatically thereafter thanks to persistence in the agent. If you move the imp to another location, just use the special URL to set the IP address again.

As to what time the server log uses… that is your local time all nice and neatly corrected. The agent time() or date() return the UTC time so need to be corrected for timezone.

Let me know what free service you use for converting IP to timezone.

That is really helpful, thanks. Yes that does get me my IP address, which I am planning to feed to the worldtime.io API to convert to time zone. Sadly I now can’t see how to send my free dev key to that API, so I am still not getting a response. Hopefully they will help me with that issue soon.

If the server known my local time, wouldn’t it be lovely if that was also exposed to the agent through a suitable API, perhaps the server api. I wonder how the server knows my local time anyway - perhaps it too is using my IP address?

Many thanks for the help,

James

Since you don’t really care about the IP address, and really just want a way to determine timezone, I found a great piece of code from @ghawkins in this thread
http://forums.electricimp.com/discussion/2376/feature-request-device-getipaddress#Item_5

That is an automatic way to find your geolocation using the google map api, based on the RSSI of the routers in your vicinity - more than a little creepy but it works well. Caveat is that it might not work in rural areas so you will need to test to see if it works for you.
Geolocation determines your timezone, so I have modified the code from @ghawkins to add timezone determination, using the Google Timezone API.

On the agent side:
`
function addColons(bssid) {
local result = bssid.slice(0, 2);

for (local i = 2; i < 12; i += 2) {
    result += ":" + bssid.slice(i, (i + 2));
}

return result;

}

device.on(“location”, function (location) {

local url = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=electric-imp&sensor=false";

foreach (network in location) {
    url += ("&wifi=mac:" + addColons(network.bssid) + "|ss:" + network.rssi);
    server.log( network.bssid + " = " + network.rssi );
}

local request = http.get(url);
local response = request.sendsync();

if (response.statuscode == 200) {
    local data = http.jsondecode(response.body);
    local timezoneURL = "https://maps.googleapis.com/maps/api/timezone/json?location=" + data.location.lat + "," + data.location.lng+"&timestamp="+time()+"&sensor=false";
    request = http.get( timezoneURL );
    response = request.sendsync();

    if (response.statuscode == 200) {
      data = http.jsondecode( response.body );
      foreach( i,v in data ) {
        server.log(i + ":" + v);
      }
      server.log("Local time is " +getLocalTime( data.rawOffset + data.dstOffset ) );
      device.send("timezoneoffset", data.rawOffset + data.dstOffset );
    }
    else
    {
        server.log("Response Error " + response.statuscode + " " + response.body );
    }
}
else
{
  server.log("Response Error " + response.statuscode + " " + response.body );
}

});

function getLocalTime( offset ) {

local dateTime = date( time() + offset,“u”);
local timeStamp = format("%02d-%02d-%02d %02d:%02d:%02d",dateTime.year,dateTime.month+1,dateTime.day, dateTime.hour, dateTime.min, dateTime.sec );
return timeStamp;
}

`

And on the device side:
`
timezoneOffset <- 0;
agent.send(“location”, imp.scanwifinetworks());

agent.on(“timezoneoffset”, function(offset) {
timezoneOffset = offset;
server.log("Imp time is : " + getTimeStamp() );
});

function getTimeStamp( ) {
local dateTime = date( localTime() );
local timeStamp = format("%02d-%02d-%02d %02d:%02d:%02d",
dateTime.year,dateTime.month+1,dateTime.day, dateTime.hour, dateTime.min, dateTime.sec );
return timeStamp;
}

function localTime(){
return time() + timezoneOffset;
}

`

That is better than having to figure out the IP address from a client HTML request that I proposed earlier. We can assume google APIs will be there for a while…

@deonsmt
Works great, thanks a lot!

Hi guys,

I happen to be working on the same problem today and repeated all the same work but wrapped it into a class.

You can also get your public ip in text from http://ifconfig.me/ip

@theorem - this actually won’t work in the way in the way you want it to.

The agent will be making the call to ifconfig.me/ip, not the imp. You’ll get back an IP address, but it will be for the IP of the agent, not the device.

I’m actually looking to get the IP address of the device, and the above code requires that I be connected to the same wireless router. Is there a way to do this without that requirement? For example, is there anyway to examine the communication from the device to the agent to extract that information?

1 Like