From 344d5e36f9fc3c15e243f95048f20d85f98f7fc4 Mon Sep 17 00:00:00 2001
From: rudolfkoenig <>
Date: Mon, 6 Feb 2012 16:48:39 +0000
Subject: [PATCH] NetIO230B by Andy
git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@1240 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
CHANGED | 1 +
FHEM/24_NetIO230B.pm | 290 +++++++++++++++++++++++++++++++++++++++++++
docs/commandref.html | 98 +++++++++++++++
3 files changed, 389 insertions(+)
create mode 100644 FHEM/24_NetIO230B.pm
diff --git a/CHANGED b/CHANGED
index f77b2dbe3..3c46bfdef 100644
--- a/CHANGED
+++ b/CHANGED
@@ -8,6 +8,7 @@
- feature: updatefhem backup is using tar+gzip now
- feature: EIB: introduce Get, interpret received values upon defined model
(by datapoint types) (Maz)
+ - feature: NetIO230B module by Andy
- 2011-12-31 (5.2)
- bugfix: applying smallscreen attributes to firefox/opera
diff --git a/FHEM/24_NetIO230B.pm b/FHEM/24_NetIO230B.pm
new file mode 100644
index 000000000..536f648e2
--- /dev/null
+++ b/FHEM/24_NetIO230B.pm
@@ -0,0 +1,290 @@
+################################################################
+# fhem-module for NetIO 230B Power Distribution Unit
+#
+# http://www.koukaam.se/showproduct.php?article_id=1502
+#
+# Usage:
+# There are 2 modes:
+#
+# (1) - define the IP, user and password directly in fhem's fhem.cfg (or UI).
+#
+# define NetIO1 [ ];
+# e.g. define NetIO1 192.168.178.2 1 admin admin;
+#
+# if you omit the user credentials, the module will look for a configuration file,
+# if no configuration file is found, it tries with 'admin', 'admin'
+#
+#
+# (2) - define your credentials using a config file.
+#
+# define NetIO1 [];
+# define NetIO1 192.168.178.2 1 /var/log/fhem/netio.conf);
+#
+# if you omit the configuration parameter, the module will look for a configuration
+# file at: /var/log/fhem/netio.conf
+#
+# NetIO230B Configuration file format:
+#
+# %config= (
+# host => "192.168.xx.xx",
+# user => "anyusername_without_spaces",
+# password => "anypassword_without_spaces"
+# );
+#
+################################################################
+# created 2012 by Andy Fuchs
+#---------
+# Changes:
+#---------
+# 2012-02-03 0.1 initial realease
+#
+
+################################################################
+package main;
+
+use strict;
+use warnings;
+use Data::Dumper;
+use LWP::UserAgent;
+use HTTP::Request;
+
+use constant PARAM_NAME => 1;
+use constant PARAM_HOST => 2;
+use constant PARAM_SOCK => 3;
+use constant PARAM_USER => 4;
+use constant PARAM_PASS => 5;
+use constant PARAM_FILE => 4;
+
+use constant DEBUG => 1;
+
+sub
+NetIO230B_Initialize($)
+{
+ my ($hash) = @_;
+
+ $hash->{SetFn} = "NetIO230B_Set";
+ $hash->{GetFn} = "NetIO230B_Get";
+ $hash->{DefFn} = "NetIO230B_Define";
+ $hash->{AttrList} = "loglevel:0,1,2,3,4,5,6";
+
+}
+
+###################################
+sub
+NetIO230B_Set($@)
+{
+ my ($hash, @a) = @_;
+
+ return "no set value specified" if(int(@a) != 2);
+ return "Unknown argument $a[1], choose one of on off " if($a[1] eq "?");
+
+ my $state = $a[1]; #initialize state to the passed parameter
+ my $result = "command was not executed - $state is not 'on' or 'off'";
+ if ($state eq "on" || $state eq "off")
+ {
+ $hash->{STATE} = $state;
+ $state = int($state eq "on");
+ #prepare the sockets default parameters; 'u' means: don't touch
+ my @values=("u","u","u","u");
+ my @sockets = @{$hash->{SOCKETS}};
+
+ foreach (@sockets) {
+ $values[$_-1] = $state;
+ $hash->{READINGS}{"socket$_"}{TIME} = TimeNow();
+ $hash->{READINGS}{"socket$_"}{VAL} = $state;
+ }
+
+ $result = NetIO230B_Request($hash, "set", join("",@values));
+ }
+
+ Log 3, "NetIO230B set @a => $result";
+
+ return undef;
+}
+
+###################################
+sub
+NetIO230B_Get($@)
+{
+ my ($hash, @a) = @_;
+ my $result = NetIO230B_Request($hash, "get");
+ Log 3, "NetIO230B get @a => $result";
+
+ return $hash->{STATE};
+}
+
+###################################
+sub
+NetIO230B_Request($@)
+{
+ my ($hash, $cmd, $list) = @_;
+ my $URL='';
+ my $log='';
+
+ $URL="http://".$hash->{HOST}."/tgi/control.tgi?l=p:". $hash->{USER}.":".$hash->{PASS}."&p=";
+ if($cmd eq "set") {
+ $URL .= "$list";
+ } else {
+ $URL .= "l";
+ }
+
+ my $agent = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1, timeout => 30);
+ my $header = HTTP::Request->new(GET => $URL);
+ my $request = HTTP::Request->new('GET', $URL, $header);
+ my $response = $agent->request($request);
+
+ $log.= "Can't get $URL -- ".$response->status_line
+ unless $response->is_success;
+
+ if($log ne "")
+ {
+ Log 3, "NetIO230B_Request: ".$log;
+ return("");
+ }
+
+ # read decoded content
+ my $buffer = $response->decoded_content;
+
+ # strip html tags
+ $buffer =~ s/<(?:[^>'"]*|(['"]).*?\1)*>//gs;
+
+ # strip leading whitespace
+ $buffer =~ s/^\s+//;
+
+ #strip trailing whitespace
+ $buffer =~ s/\s+$//;
+
+ return $buffer if ($cmd eq "set");
+
+ #+++todo
+ #555 FORBIDDEN
+
+ #split the result into an array
+ my @values=split(/ */,$buffer);
+
+ #save the values to the readings hash
+ my $state = "???";
+ my @sockets = @{$hash->{SOCKETS}};
+ foreach (@sockets) {
+ $hash->{READINGS}{"socket$_"}{TIME} = TimeNow();
+ $hash->{READINGS}{"socket$_"}{VAL} = $values[$_-1];
+ if ($state == "???") { #initialize state
+ $state = $values[$_-1];
+ } else {
+ $state = "???" if ($values[$_-1] != $state); #if states are mixed show ???
+ }
+ }
+
+ $hash->{STATE} = $state;
+
+ # debug output
+ #my %k = %{$hash->{READINGS}};
+ #foreach my $r (sort keys %k) {
+ # Log 1, "$r S: $k{$r}{VAL} T: $k{$r}{TIME}";
+ #}
+
+ return $buffer;
+}
+
+### _Define routing is called when fhem starts -> 'reloading' of the module does not call the define routine!!
+###
+sub
+NetIO230B_Define($$)
+{
+ my ($hash, $def) = @_;
+ my @a = split("[ \t][ \t]*", $def);
+ my $paramCount = int(@a);
+
+ Log 3, "Wrong syntax: use 'define NetIO230B [ ]' or 'define NetIO230B [ ]'" if(int(@a) < 4); #5 = mit user/pass #4 = mit config
+
+ #provide some default settings
+ $hash->{CONFIGFILEPATH} = "/var/log/fhem/netio.conf"; #default file path is /var/log/fhem/netio.conf
+ $hash->{USER} = "admin";
+ $hash->{PASS} = "admin";
+ @{$hash->{SOCKETS}} = (1,2,3,4); #default to all sockets
+
+ #mandatory parameter: 'HOST'
+ $hash->{HOST} = $a[PARAM_HOST]; #can be overridden, if using a config file
+
+ #mandatory parameter: 'SOCKET #'; negative numbers are ignored
+ my $buf = $a[PARAM_SOCK];
+ if (($buf =~ m/^\d+$/) && ($buf >=0)) { #make sure input value is a positive number
+
+ if ($buf == 0) #input socket '0' is used as 'all'
+ {
+ @{$hash->{SOCKETS}} = (1,2,3,4); #use this number as 'array of socket-numbers' to operate on
+
+ } elsif ($buf <= 4) #input socket is a single number <=4
+ {
+ @{$hash->{SOCKETS}} = ($buf); #use this number as 'array of socket-numbers' to operate on
+
+ } else {
+
+ @{$hash->{SOCKETS}} = split("",$buf); #convert the input values to an array of sockets to operate on
+ }
+ }
+
+ #optional parameter: 'CONFIGFILE_NAME_or_PATH'
+ if ($paramCount == 5) #seems a config file is passed
+ {
+ $hash->{CONFIGFILEPATH} = $a[PARAM_FILE] if defined($a[PARAM_FILE]);;
+ }
+
+ #optional parameters: 'USER and PASS'
+ if ($paramCount != 6)
+ {
+ my %config = NetIO230B_GetConfiguration($hash);
+ if (%config) {
+ $hash->{HOST} = $config{host} if (defined($config{host}));
+ $hash->{USER} = $config{user} if (defined($config{user}));
+ $hash->{PASS} = $config{password} if (defined($config{password}));
+ } else {
+
+ Log 3, "NetIO230B: Configuration could not be read. Trying default values...\n";
+ }
+
+ } else {
+ #in any other case
+ $hash->{USER} = $a[PARAM_USER] if defined($a[PARAM_USER]);
+ $hash->{PASS} = $a[PARAM_PASS] if defined($a[PARAM_PASS]);
+ }
+
+ Log 3, "NetIO230B: device opened at host: $hash->{HOST} => @a\n";
+
+ return undef;
+}
+##########################################
+#
+# NetIO230B Configuration-Format:
+#
+# %config= (
+# host => "192.168.xx.xx",
+# user => "anyusername_without_spaces",
+# password => "anypassword_without_spaces"
+# );
+#
+#
+##########################################
+
+### _GetConfiguration reads a plain text file containing arbitrary information
+sub
+NetIO230B_GetConfiguration($)
+{
+ my ($hash)= @_;
+ my $configfilename = $hash->{CONFIGFILEPATH};
+
+ if(!open(CONFIGFILE, $configfilename))
+ {
+ Log 3, "NetIO230B: Cannot open settings file '$configfilename'.";
+ return ();
+ }
+ my @configfile=;
+ close(CONFIGFILE);
+
+ my %config;
+ eval join("", @configfile);
+
+ return %config;
+}
+
+1;
diff --git a/docs/commandref.html b/docs/commandref.html
index 0a35675f7..72f7db4ff 100644
--- a/docs/commandref.html
+++ b/docs/commandref.html
@@ -105,6 +105,7 @@
M232
M232Counter
M232Voltage
+ NetIO230B
OREGON
OWFS
OWTEMP
@@ -6492,6 +6493,103 @@ Terminating
loglevel
+
+
+
+NetIO230B
+
+
+ fhem-module for NetIO 230B Power Distribution Unit (see: NetIO 230B
+ (koukaam.se))
+
+ Note: this module needs the HTTP::Request and LWP::UserAgent perl modules.
+
+ Please also note: the PDU must use firmware 3.1 or later and set to unencrypted mode.
+
+
+ Define
+
+
+ define <name> NetIO230B <ip-address> <socket number
+ > [<user name> <password>]
+
+ define <name> NetIO230B <ip-address> <socket number
+ > [<config file path>]
+
+
+ Defines a switching device, where sockets can be switched
+
+
+ - separately (just use 0-4 as socket number)
+ - all together (use 1234 as socket number)
+ - in arbitrary groups (e.g 13 switches socket 1 and 3, 42
+ switches socket 2 and 4, etc...), invalid numbers are
+ ignored
+
+
+ User name and password are optional. When no user name or
+ password is passed, the module looks for a configfile at
+ '/var/log/fhem/netio.conf'. If no config file is found, it
+ uses 'admin/admin' as user/pass, since this is the default
+ configuration for the device.
+
+ Alternatively you can pass a path to a configfile instead of
+ the user/pass combo. (e.g. /var/tmp/tmp.conf)
+ Configfile-Format:
+
+
+ %config= (
+ host => "192.168.61.40",
+ user => "admin",
+ password => "admin"
+ );
+
(All settings optional)
+
+
+ Examples:
+
+ define Socket3 NetIO230B 192.168.178.10 3
+ define Socket1_and_4 NetIO230B 192.168.178.10 14
+ define coffeemaker NetIO230B 192.168.178.10 1 username secretpassword
+ define coffeemaker_and_light NetIO230B 192.168.178.10 23 /var/log/kitchen.conf
+
+
+
+
+
+ Get
+
+ get <name> state
+
+ returns the state of the socket(s)
+
+ Example:
+
+ get coffeemaker_and_light
=> on or off
+
+
+
+
+
+ Set
+
+ set <name> <value>
+
+ where value
is one of:
+
+ on
+ off
+
+ Examples:
+
+ set coffeemaker_and_light on
+
+
+
+
+
+
TellStick