Energenie LAN Management Power Strip (4-Way) - Plug in (Idea)

Hi all,

I wrote some Perl scripts that can power on/off those plugs, see [url=http://forum.micasaverde.com/index.php?topic=16888.0]http://forum.micasaverde.com/index.php?topic=16888.0[/url] (the post is not yet approved). Thsi is not using the webGUI (which is an approach I don’t really like), but uses the documented protocol on port 5000 in their SDK (which is a bit messy and weird, involving some simple challenge&response authentication). I don’t know about LUA, but I think it should be possible to dapt the code accordingly.

Cheers, Andy

Thanks @klaymen

I’ve quoted your post in the other thread here to, so we can see if it can be converted to some LUA which people with this socket can use.

[quote=“klaymen, post:11, topic:177214”]Hi all,

I got this device too. Using the protocol description I successfully wrote a small perl script that can turn on and off the plugs using the protocol on port 5000 (not the webserver itself). If your’e interested, it looks like this (should not be difficult to implement it in any other language), $pass and $ip must be filled in of course:

use strict;
use IO::Socket::INET;

my $pass = "...";
my $ip = "...";

sub response($$)
{
  my @d = map (ord, split //,shift);
  my @k = map (ord, split //,shift);
  my $v1 = (($d[0]^$k[2]) * $k[0])  ^  ($k[6] | ($k[4]<<8))  ^  $d[2];
  my $v2 = (($d[1]^$k[3]) * $k[1])  ^  ($k[7] | ($k[5]<<8))  ^  $d[3];
  return join "",map(chr, ($v1%256,$v1>>8,$v2%256,$v2>>8));
}

sub encrypt($$$)
{
  my @d = map (ord, split //,shift);
  my @k = map (ord, split //,shift);
  my @t = map (ord, split //,shift);
  my @r = (0,0,0,0);
  my $x;
  for (my $i=0; $i<4; $i++)
  {
    $x = $d[3-$i];
    $x ^=  $t[2];
    $x += $t[3];
    $x ^= $k[0];
    $x += $k[1];
    $r[$i] = 0xff & $x;
  }
  return join "",map(chr, @r);
}

sub decrypt($$$)
{
  my @d = map (ord, split //,shift);
  my @k = map (ord, split //,shift);
  my @t = map (ord, split //,shift);
  my @r = (0,0,0,0);
  my $x;
  for (my $i=0; $i<4; $i++)
  {
    $x = $d[$i];
    $x -= $k[1];
    $x ^= $k[0];
    $x -= $t[3];    
    $x ^= $t[2];
    $r[3-$i] = 0xff & $x;   
  }
  return join "",map(chr, @r);
}

sub setPlug($$$)
{
  my $ip = shift;
  my $idx = shift;
  return 0 if $idx<0 or $idx>3; # plugs 0-3
  my $flg = shift;
  return 0 if $flg<0 or $flg>2; # 0: turn off, 1: turn on, 2: toggle

  my $done = 0;
  while (!$done)
  {
	  my $s;
	  eval
	  {
		local $SIG{ALRM} = sub { die 'Timed Out'; };
		alarm 10; 
		my ($t,$d);
		$s =  new IO::Socket::INET (
		  PeerHost => $ip,
		  PeerPort => '5000',
		  Proto => 'tcp',
		) or return 0;

		$s->send("\x11");
		$s->recv($t,4);

		$s->send(response($t,$pass));
		$s->recv($d,4);
		$d = decrypt($d,$pass,$t);
  
		my $ctrl = "\x04\x04\x04\x04";  # default is: no action on any plug
		if ($flg==0) # turn off, unless it already is off
		{
		  substr($ctrl,$idx,1) = "\x02" unless substr($d,$idx,1) eq "\x82";
		}
		if ($flg==1) # turn on, unless it alredy is on
		{
		  substr($ctrl,$idx,1) = "\x01" unless substr($d,$idx,1) eq "\x41";
		}
		if ($flg==2) # toggle
		{
		  substr($ctrl,$idx,1) = chr((ord(substr($d,$idx,1))&1) + 1);
		}

		$s->send(encrypt($ctrl,$pass,$t));
		$s->recv($d,4);
		$d = decrypt($d,$pass,$t);
		$done=1;

		$s->send("\x01\x02\x03\x04");
		alarm 0;
	  };
	  alarm 0;
      $s->close() if defined $s;
  }
  return 1;
}


setPlug($ip,0,0); # turn off plug 1
setPlug($ip,0,1); # turn on plug 1
setPlug($ip,0,2); # toggle plug 1

The while/eval construct is just there to repeat the TCP connection in case of a problem. You might want to increase/decrase the “alarm 10” value - in this setup, the connection is re-tries after 10 seconds if it does not succeeds (timeout).

Hope it helps,

Andy[/quote]

Sadly I’m still learning Lua and have little knowledge of Perl. But I’m keen to get this working with Vera.

It’s taken me a while, but I think I’ve finally found out how to do it…

http://www.linux-hardware-guide.com/uk/2014-04-19-energenie-eg-pm2-lan-programmable-6x-ip-outlet-socket-lan

The EnerGenie EG-PM2-LAN is a programmable 6-times multiple socket outlet, which can be accessed via Ethernet. In contrast to the USB version there is no dedicated tool available for this LAN version. However, it is possible to send commands to the Web interface, which is embedded in the EG-PM2-LAN. In the following it is described how these commands can be sent via ?curl?.

First, the web server needs a login with a password (?PASSWORD? is used in the following)

curl -sd ‘pw=PASSWORD’ http://EG-PM2-LAN-IP-Adress | fgrep -q Status

The return value should be ?true?. As one can see, the password is sent unencrypted, which shows the low safety measures of the EG-PM2-LAN and could be a drawback for certain scenarios.

The integrated web server does not support sessions. Instead, after transmitting the password each process from the same IP address of this login can access the EG-PM2-LAN. Furthermore, all other IPs are blocked, while this login is still active. After some minutes of idling the login times out and a new login is necessary to access the web frontend.

Now, it is possible to switch via shell command one of the sockets (X = 1 ? 4) on (Y=1) or off (Y=0). E.g., if socket 3 should be powered on, this is done by the command:

curl -sd ‘cte3=1’ http://EG-PM2-LAN-IP-Adresse | fgrep -q Status
or in general by

curl -sd ‘cteX=Y’ http://EG-PM2-LAN-IP-Adresse | fgrep -q Status
The logout is achieved by:

curl -s http://EG-PM2-LAN-IP-Adresse | fgrep -q password

And now I need to see if I can get it to work via Vera,.

So far I’ve been trying to get the fist one to work by using os.execute () but no joy. My ‘Lua Test’ result is below, I’ve tried a few things, but not sure what I’m missing…

LuaTest 1.5.2

Lua file: /nas/luaenergenie.lua

Results
Code error: Line 2: ‘)’ expected near ‘pw’

Print output
(none)

Code
1
2 os.execute(‘curl -sd ‘pw=1’ http://192.168.1.90 | fgrep -q Status’)

My Luatest result is below, I've tried a few things, but not sure what I'm missing...

The argument for os.execute(…) needs to be a single string and yours isn’t. Try something like:

os.execute("curl -sd 'pw=1' http://192.168.1.90 | fgrep -q Status")

Thanks Rex,

I had tried speech marks around the IP address etc., but missed that one :frowning:

It seemed to go through alright, but it does not seem to be doing anything to the power socket, I try to turn off Socket 3. Humm, I’m going to need to keep playing…

LuaTest 1.5.2

Lua file: /nas/luaenergenie.lua

Results
No errors
Runtime: 164.3 ms
Code returned: nil

Print output
Receive:

Code
1
2 os.execute(“curl -sd ‘pw=1’ http://192.168.1.90 | fgrep -q Status”)
3
4 os.execute(“curl -sd ‘cte3=0’ http://192.168.1.90 | fgrep -q Status”)
5
6 print (“Receive:”, data, rerr)

Reading an old post I found from @Guessed, (http://forum.micasaverde.com/index.php/topic,17627.msg138882.html#msg138882) it seems calling Curl, via a shell process places an overhead on Vera, so if I’ve understood his direction correctly, I would need to ensure any coding I do has this at the beginning? Does that sound right.

local url = require("socket.url")
local socket = require("socket")
local http = require("socket.http")
local ltn12 = require("ltn12")

-- 5 Second timeout
http.TIMEOUT = 5

Launching a shell process does have an overhead. May not be a problem if it only happens a few times in a day but not great for frequent use.

@Guessed was suggesting that it would be preferable to use the Post method with Lua Socket. He provided links to examples.

Because your device requires a log-on prior to accepting a command, the issue may be one of timing. You need to understand the timing and return values before you can code it properly. Do the cURL commands work when issued from Vera’s command line? Try them without the | fgrep -q Status suffix as well.

Hi
I managed to get the following working in Zerobrane lua IDE but so far no success running it in a scene, in case its any help :slight_smile: You’ll need to fill in your details for SERVERNAME, PASSWORD and ENERGENIEIPADDRESS. This is just a first working example, at the moment just turning socket number 1 (cte1) on (change cte1=0 to turn off) - line 4.

local http = require “socket.http”
local ltn12 = require “ltn12”
local passbody = “SERVERNAME&pw=PASSWORD”
local sw1body = “cte1=1”
local respbody = {}
local body, code, headers, status = http.request {
method = “POST”,
url = “http://ENERGENIEIPADDRESS/login.html”,
source = ltn12.source.string(passbody),
headers =
{
[“Accept”] = “/”,
[“Accept-Encoding”] = “gzip, deflate”,
[“Accept-Language”] = “en-us”,
[“Content-Type”] = “application/x-www-form-urlencoded”,
[“content-length”] = string.len(passbody)
},
sink = ltn12.sink.table(respbody)
}
socket.sleep(2)
local b, c, h, s = http.request {
method = “POST”,
url = “http://ENERGENIEIPADDRESS”,
source = ltn12.source.string(sw1body),
headers =
{
[“Accept”] = “/”,
[“Accept-Encoding”] = “gzip, deflate”,
[“Accept-Language”] = “en-us”,
[“Content-Type”] = “application/x-www-form-urlencoded”,
[“content-length”] = string.len(sw1body)
},
sink = ltn12.sink.table(respbody)
}

Hi @ChrisAB

Finally found time to have a go with this, but I’m not sure what is the Servername would be ?

I know the IP and Password ?

UPDATE : Scrap that I found it, the defaults are :slight_smile:

SERVERNAME = Server 1
PASSWORD = 1

Sadly no joy, I tried it in the test Lua window, it was sent successfully, but it had no affect on my Energenie EG-PSM-LAN . The code below show the default server name and password.

local http = require "socket.http" local ltn12 = require "ltn12" local passbody = "Server 1&pw=1" local sw1body = "cte1=1" local respbody = {} local body, code, headers, status = http.request { method = "POST", url = "http://192.168.1.90/login.html", source = ltn12.source.string(passbody), headers = { ["Accept"] = "*/*", ["Accept-Encoding"] = "gzip, deflate", ["Accept-Language"] = "en-us", ["Content-Type"] = "application/x-www-form-urlencoded", ["content-length"] = string.len(passbody) }, sink = ltn12.sink.table(respbody) } socket.sleep(2) local b, c, h, s = http.request { method = "POST", url = "http://192.168.1.90", source = ltn12.source.string(sw1body), headers = { ["Accept"] = "*/*", ["Accept-Encoding"] = "gzip, deflate", ["Accept-Language"] = "en-us", ["Content-Type"] = "application/x-www-form-urlencoded", ["content-length"] = string.len(sw1body) }, sink = ltn12.sink.table(respbody) }

Hi, sorry, haven’t been on the forum for a while.
I have also posted this under http://forum.micasaverde.com/index.php/topic,27291.msg195079/topicseen.html#msg195079
I can’t get it to work in Vera either and so far no solution has been suggested ???
I’ll post again if I get anywhere…
Cheers

I’ve been attempting this too. Whilst I also get the code to work in ZeroBrane, I can’t get it to work using the Test Luup Code in Vera. I put some luup.log into the code, and the statusMsg returns “timeout” at the very first step (login.htm). Unfortunately I know nothing about Luup coding so I have no idea why timeout occurs only in Vera (despite http.TIMEOUT = 5 being defined). :cry:

I’m not able to test this fully tonight, and it might be nothing, but the first page I go to, with the server name and the password prompt on it, looks to be http://192.168.1.90/energenie.html not http://192.168.1.90/login.html

http://192.168.1.90/login.html is the one I’m taken to after I’ve logged in…

UPDATE - Actually it looks like both of the above pages and anything you want to put after the IP e.g http://192.168.1.90/micasaverde.html will bring up the password prompt (wierd!!)

I tried different urls with ZeroBrane LUA test environment and they all seemed to work. I then tried it with my Internet browser and the page doesn’t respond any more! I think messing about with testing code has partially hung the EnerGenie – not a good sign for robust reliability… Now that woud explain why Vera is seeing timeouts :wink:
Wierdly the iPhone app still definitely works and control the switches, but presumably this uses a different port via the cloud service.
I’ll have another go tomorrow. If the EnerGenie doesn’t recover overnight, I’ll have to power cycle it (or maybe there is a reset button?).

Some success !!!

Using a very simple ipad app, I can turn a socket on and off by sending (POST) the following to this URL

http://192.168.1.90/status.html

Parameter pw = 1
Parameter cte2 = 0 (for off)

It only bloody works - socket 2 is turned off !!

Now, I’m bound to have missed something obvious, but so far, so good. Is anyone able to verify ?

Using that simply app on the iPad…

It looks like I have to POST the pw=1 parameter to this URL http://192.168.1.90/login.html

And then once logged in i can send the socket command cte1=0 to this URL http://192.168.1.90/status.html

Seems like different commands to different URLs.

The login requests seems to timeout after a while, I’ll need to try and work out how long that is.

I’m not going to be able to do much more during today, but I will hopefully try later

After pressing reset button on the Energenie, the web front end worked ok. However, as soon as I run this Luup code in Vera, the Energiene web server locks up again after a single attempt. I don’t understand why Vera causes the Energenie to lock up in contrast to same code run from ZeroBrane lua does not. For me, I think this is a dead end to using port 80. Perhaps using the separate API for Power Manager Client on port 5000 is the better way to go, but far too complex for me to attempt it.

local url = require("socket.url")
local socket = require("socket")
local http = require("socket.http")
local ltn12 = require("ltn12")
local postBody = "server=GENIE&pw=1"
local controlURL = "http://192.168.0.246/energenie.html"

-- 5 Second timeout
http.TIMEOUT = 5

local resultTable = {}
local status, statusMsg = http.request{
    url = controlURL,
    sink = ltn12.sink.table(resultTable),
    method = "POST",
    headers = {
                        ["Accept"] = "*/*",
                        ["Accept-Encoding"] = "gzip, deflate",
                        ["Accept-Language"] = "en-us",
                        ["Content-Type"] = "application/x-www-form-urlencoded",
                        ["Content-Length"] = postBody:len()
                },
    source = ltn12.source.string(postBody),
  }

luup.log("Status Message1 = " .. tostring(statusMsg))
socket.sleep(2)
luup.log("Status Message2 = " .. tostring(statusMsg))

I’m not able to have a play at the moment, but I can’t help but think the code could be much easier than that. Using the iPad, it looks like two basic POST commands were sent and it worked?!?

UPDATE - I was hoping it could be something like this… Taken from here → http://wiki.micasaverde.com/index.php/Luup_Scenes_Events#Invoke_HTTP_URL_with_POST_request_.28Method_3.29

[code]local http = require(“socket.http”)
http.TIMEOUT = 5
result, status = http.request(“http://192.168.1.90/login.html”, “pw=1”)

luup.call_delay(“Socket2on”,10)

function Socket2on()
http.TIMEOUT = 5
result, status = http.request(“http://192.168.1.90/status.html”, “cte2=1”)
end
[/code]

… But all this seems to have done is make my Energenie unresponsive now :slight_smile:

UPDATE 2 - it looks like the Energenie can only have one session (from one device running) at any one time, I attempted another login from my PC while I was using it on my iPad - so it tells you."

Impossible to login - there is an active session with this device at the moment"

It’s poosible that could play a key part in the testing. If I have the iPad logged in when testing code on Vera…

Wow, coming back to this thread that I had started a while back - I’ve stumbled across something that works and it seems remarkably simple. Just a short line of code which you can run via the command line :Dn - which mean you can call these in vera by using os.execute(“curl command”)

The first thing you need to do is login (the default password is 1, so I have left it as that for those examples)

It’s seems you can do that either via curl,

curl -s -d "pw=1" http://192.168.1.90/login.html

or wget

wget -q -O - --post-data="pw=1" http://192.168.1.90/login.html 

And the to turn the sockets on or off you set the value of your target to either 1 or 0 e.g.

Turn on socket 4 (via curl)

curl -s -d "cte4=1" http://192.168.1.90/

Turn off socket 4 (via curl)

curl -s -d "cte4=0" http://192.168.1.90/

Turn on socket 4 (via wget)

wget -q -O - --post-data="cte4=1" 'http://192.168.1.90/'

Turn off socket 4 (via wget)

wget -q -O - --post-data="cte4=0" 'http://192.168.1.90/'

Now if anyone is able to work this into a plug in, when the login is refreshed every few minutes . There seems to be a way to check the state of the sockets, but I could not get this to work

curl -s -d "pw=1" http://192.168.1.90/login.html | \ sed -n -E -e 's/.*var sockstates = \[([01]),([01]),([01]),([01])\].*/\1 \2 \3 \4/p' | \ sed -e 's/0/off/g' -e 's/1/on /g' | \ xargs printf -- "\n-1- -2- -3- -4-\n%3s %3s %3s %3s\n" wget -q -O - --post-data="pw=1" http://192.168.1.90/login.html | \ sed -n -E -e 's/.*var sockstates = \[([01]),([01]),([01]),([01])\].*/\1 \2 \3 \4/p' | \ sed -e 's/0/off/g' -e 's/1/on /g' | \ xargs printf -- "\n-1- -2- -3- -4-\n%3s %3s %3s %3s\n"

A big thank you to the following sources

[ul][li]https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fwiki.ffdo.de%2FTechnik%2FRichtfunk%2FGeraetekonfiguration%2FEG-PM2-LAN[/li]
[li]Code for Energenie LAN Powerstrip - Domoticz

It took me 8 years, 2 months to get there, but I finally created a plugin for Energenie LAN Switch :slight_smile:

1 Like