From ed15c50a02ca3789ea2103c361e4b8f878b310ed Mon Sep 17 00:00:00 2001 From: akw <> Date: Mon, 3 Mar 2014 19:24:20 +0000 Subject: [PATCH] Added modules ENECSYSGW and ENECSYSINV git-svn-id: https://svn.fhem.de/fhem/trunk@5115 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/30_ENECSYSGW.pm | 208 +++++++++++++++++++++++++++++++++++++ fhem/FHEM/31_ENECSYSINV.pm | 179 +++++++++++++++++++++++++++++++ fhem/MAINTAINER.txt | 2 + 3 files changed, 389 insertions(+) create mode 100644 fhem/FHEM/30_ENECSYSGW.pm create mode 100644 fhem/FHEM/31_ENECSYSINV.pm diff --git a/fhem/FHEM/30_ENECSYSGW.pm b/fhem/FHEM/30_ENECSYSGW.pm new file mode 100644 index 000000000..d2773ad9f --- /dev/null +++ b/fhem/FHEM/30_ENECSYSGW.pm @@ -0,0 +1,208 @@ +# 30_ENECSYSGW.pm +# ENECSYS Gateway Device +# +# (c) 2014 Arno Willig +# +# $Id$ + +package main; + +use strict; +use warnings; +use POSIX; +use MIME::Base64; +use XML::Simple; + +sub ENECSYSGW_Initialize($) +{ + my ($hash) = @_; + + # Provider + $hash->{ReadFn} = "ENECSYSGW_Read"; + $hash->{WriteFn} = "ENECSYSGW_Read"; + $hash->{Clients} = ":ENECSYSDevice:"; + + # Consumer + $hash->{DefFn} = "ENECSYSGW_Define"; + $hash->{NOTIFYDEV} = "global"; + $hash->{NotifyFn} = "ENECSYSGW_Notify"; + $hash->{UndefFn} = "ENECSYSGW_Undefine"; + $hash->{AttrList} = "disable:1"; +} + +sub ENECSYSGW_Read($@) +{ + my ($hash,$name,$id,$obj)= @_; + return ENECSYSGW_Call($hash); +} + +sub ENECSYSGW_Define($$) +{ + my ($hash, $def) = @_; + my @args = split("[ \t]+", $def); + return "Usage: define ENECSYSGW [interval]" if(@args < 3); + + my ($name, $type, $host, $interval) = @args; + + $interval = 10 unless defined($interval); + if ($interval < 5) { $interval = 5; } + + $hash->{STATE} = 'Initialized'; + $hash->{Host} = $host; + $hash->{INTERVAL} = $interval; + + $hash->{Clients} = ":ENECSYSINV:"; + my %matchList = ( "1:ENECSYSINV" => ".*" ); + $hash->{MatchList} = \%matchList; + + if( $init_done ) { + ENECSYSGW_OpenDev( $hash ) if( !AttrVal($name, "disable", 0) ); + } + return undef; +} + +sub ENECSYSGW_Notify($$) +{ + my ($hash,$dev) = @_; + my $name = $hash->{NAME}; + my $type = $hash->{TYPE}; + + return if($dev->{NAME} ne "global"); + return if(!grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}})); + return undef if( AttrVal($name, "disable", 0) ); + + ENECSYSGW_OpenDev($hash); + return undef; +} + +sub ENECSYSGW_Undefine($$) +{ + my ($hash,$arg) = @_; + RemoveInternalTimer($hash); + return undef; +} + +sub ENECSYSGW_OpenDev($) +{ + my ($hash) = @_; + $hash->{STATE} = 'Connected'; + ENECSYSGW_GetUpdate($hash); + return undef; +} + +sub ENECSYSGW_GetUpdate($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + if(!$hash->{LOCAL}) { + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+$hash->{INTERVAL}, "ENECSYSGW_GetUpdate", $hash, 0); + } + ENECSYSGW_Call($hash); +} + +sub ENECSYSGW_Call($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + return undef if($attr{$name} && $attr{$name}{disable}); + my $URL = "http://" . $hash->{Host} . "/ajax.xml"; + my $ret = GetFileFromURL($URL, 5, undef, 1 ); + + if( !defined($ret) ) { + return undef; + } elsif($ret eq '') { + return undef; + } elsif($ret =~ /^error:(\d){3}$/) { + return "HTTP Error Code " . $1; + } + my $parser = new XML::Simple; + my $data = $parser->XMLin($ret,SuppressEmpty => 1); + my $rmsg = $data->{zigbeeData}; + my $ConnectionStatus = $data->{connectionStatus}; + my $ConnectionUptime = $data->{connectionUptime}; + my $devicesInNetwork = $data->{devicesInNetwork}; + my $timeSinceReset = $data->{timeSinceReset}; + + readingsBeginUpdate($hash); + readingsBulkUpdate($hash,"ConnectionStatus",$ConnectionStatus); + readingsBulkUpdate($hash,"ConnectionUptime",$ConnectionUptime); + readingsBulkUpdate($hash,"devicesInNetwork",$devicesInNetwork); + readingsBulkUpdate($hash,"timeSinceReset",$timeSinceReset); + readingsEndUpdate($hash, 1); + + # Testing $rmsg = "WS=F4_3BQCaxjQAABMIIQEAAAIrFDADiAAAEAANAywyAOUOApsBJAAAB8"; + + return undef unless defined $rmsg; + + $rmsg =~ s/\r//g; + $rmsg =~ s/\n//g; + $rmsg =~ s/_/\//g; + $rmsg =~ s/-/+/g; + + readingsSingleUpdate($hash,"rawReading",$rmsg,1); + + if ($rmsg =~ /^WS/ && length($rmsg)==57) { + $rmsg = unpack('H*', decode_base64(substr($rmsg,3,54))).'A'; + + Log3 $name, 4, "$name: Zigbee raw: $rmsg"; + + my $serial = hex(unpack("H*", pack("V*", unpack("N*", pack("H*", substr($rmsg,0,8)))))); + + my $dmsg = $rmsg; + Log3 $name, 4, "$name: $dmsg"; + $hash->{"${name}_MSGCNT"}++; + $hash->{"${name}_TIME"} = TimeNow(); + $hash->{RAWMSG} = $rmsg; + my %addvals = (RAWMSG => $rmsg); + Dispatch($hash, $dmsg, \%addvals); + } + + if ($rmsg =~ /^WS/ && length($rmsg)!=57) { # other inverter strings (startup?) + Log3 $name, 4, "$name: Zigbee unknown data"; + } + + if ($rmsg =~ /^WZ/) { # gateway data + Log3 $name, 4, "$name: Zigbee gateway data"; + } + return undef; +} + +1; + +=pod +=begin html + + +

ENECSYSGW

+
    + Module to access the ENECSYS gateway (http://www.ENECSYS.com/products/gateway/).

    + + The actual micro-inverter devices are defined as ENECSYSINV devices. + +

    + All newly found inverter devices are autocreated and added to the room ENECSYSINV. + + +

    + + Define +
      + define <name> ENECSYSGW [<host>] [<interval>]
      +
      + + Defines an ENECSYSGW device with address <host>.

      + + The gateway will be polled every <interval> seconds. The default is 10 and minimum is 5.

      + + Examples: +
        + define gateway ENECSYSGW 10.0.1.1
        +
      +

    +

+ +=end html +=cut diff --git a/fhem/FHEM/31_ENECSYSINV.pm b/fhem/FHEM/31_ENECSYSINV.pm new file mode 100644 index 000000000..038cbe88c --- /dev/null +++ b/fhem/FHEM/31_ENECSYSINV.pm @@ -0,0 +1,179 @@ +# 30_ENECSYSINV.pm +# ENECSYS Inverter Device +# +# (c) 2014 Arno Willig +# +# $Id$ + +package main; + +use strict; +use warnings; +use POSIX; +use SetExtensions; + +sub ENECSYSINV_Initialize($) +{ + my ($hash) = @_; + # Provider + + # Consumer + $hash->{Match} = ".*"; + $hash->{DefFn} = "ENECSYSINV_Define"; + $hash->{UndefFn} = "ENECSYSINV_Undefine"; + $hash->{ParseFn} = "ENECSYSINV_Parse"; + $hash->{AttrList} = "IODev ".$readingFnAttributes; + + $hash->{AutoCreate} = { + "ENECSYSINV.*" => { + GPLOT => "power4:Power,", + FILTER => "%NAME:dcpower:.*" + #ATTR => "event-min-interval:dcpower:120" + } + }; +} + + +sub ENECSYSINV_Define($$) +{ + my ($hash, $def) = @_; + my @args = split("[ \t]+", $def); + my $iodev; + my $i = 0; + foreach my $param ( @args ) { + if ($param =~ m/IODev=(.*)/) { + $iodev = $1; + splice( @args, $i, 1 ); + last; + } + $i++; + } + return "Usage: define ENECSYSINV " if(@args < 3); + + my ($name, $type, $code, $interval) = @args; + + $hash->{STATE} = 'Initialized'; + $hash->{CODE} = $code; + + AssignIoPort($hash,$iodev) if (!$hash->{IODev}); + if(defined($hash->{IODev}->{NAME})) { + Log3 $name, 3, "$name: I/O device is " . $hash->{IODev}->{NAME}; + } else { + Log3 $name, 1, "$name: no I/O device"; + } + $modules{ENECSYSINV}{defptr}{$code} = $hash; + return undef; +} + +sub ENECSYSINV_Undefine($$) +{ + my ($hash,$arg) = @_; + my $code = $hash->{ID}; + $code = $hash->{IODev}->{NAME} ."-". $code if( defined($hash->{IODev}->{NAME}) ); + delete($modules{ENECSYSINV}{defptr}{$code}); + return undef; +} + +sub ENECSYSINV_Parse($$) +{ + my ($iodev, $msg, $local) = @_; + my $ioName = $iodev->{NAME}; + + my $serial = hex(unpack("H*", pack("V*", unpack("N*", pack("H*", substr($msg,0,8)))))); + + + my $hash = $modules{ENECSYSINV}{defptr}{$serial}; + if(!$hash) { + my $ret = "UNDEFINED ENECSYSINV_$serial ENECSYSINV $serial"; + Log3 $ioName, 3, "$ret, please define it"; + DoTrigger("global", $ret); + return ""; + } + + + foreach my $mod (keys %{$modules{ENECSYSINV}{defptr}}) { + my $hash = $modules{ENECSYSINV}{defptr}{"$mod"}; + if ($hash && $hash->{CODE} == $serial) { + my $time1 = hex(substr($msg,18,4)); + my $time2 = hex(substr($msg,30,6)); + my $dcCurrent = 0.025*hex(substr($msg,46,4)); #25 mA units? + my $dcPower = hex(substr($msg,50,4)); + my $efficiency = 0.001*hex(substr($msg,54,4)); + my $acFreq = hex(substr($msg,58,2)); + my $acVolt = hex(substr($msg,60,4)); + my $temperature = hex(substr($msg,64,2)); + my $lifekWh = (0.001*hex(substr($msg,66,4)))+hex(substr($msg,70,4)); + my $acPower = $dcPower * $efficiency; + my $dcVolt = sprintf("%0.2f",$dcPower / $dcCurrent); + + readingsBeginUpdate($hash); + readingsBulkUpdate($hash,"dccurrent",$dcCurrent); + readingsBulkUpdate($hash,"dcpower",$dcPower); + readingsBulkUpdate($hash,"dcvolt",$dcVolt); + readingsBulkUpdate($hash,"acfrequency",$acFreq); + readingsBulkUpdate($hash,"acvolt",$acVolt); + readingsBulkUpdate($hash,"acpower",$acPower); + readingsBulkUpdate($hash,"lifetime",$lifekWh); + readingsBulkUpdate($hash,"efficiency",$efficiency); + readingsBulkUpdate($hash,"temperature",$temperature); + readingsBulkUpdate($hash,"state",$dcPower); + readingsEndUpdate($hash, 1); + + return $hash->{NAME}; + + } + } +} +1; + +=pod +=begin html + + +

ENECSYSINV

+
    +
    + + Define +
      + define <name> ENECSYSINV <id> [<interval>]
      +
      + + Defines an micro-inverter device connected to an ENECSYSGW.

      + + Examples: +
        + define SolarPanel1 ENECSYSINV 100123456
        +
      +

    + + + Readings +
      +
    • acfrequency
      + the alternating current frequency reported from the device. Should be around 50 Hz in Europe.
    • +
    • acpower
      + the alternating current power
    • +
    • acvolt
      + the alternating current voltage
    • +
    • dccurrent
      + the direct current
    • +
    • dcpower
      + the direct current power
    • +
    • dcvolt
      + the direct current voltage
    • +
    • efficiency
      + the efficiency of the inverter
    • +
    • lifetime
      + the sum of collected energy of the inverter
    • +
    • temperature
      + the temperature of the inverter
    • +
    • state
      + the current state (equal to dcpower)
    • +

    + + +

+ +=end html +=cut diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index 1fd679f61..0cb6e6351 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -87,7 +87,9 @@ FHEM/23_WEBIO_12DIGITAL.pm sachag http://forum.fhem.de Sonstiges FHEM/23_WEBTHERM.pm betateilchen/sachag http://forum.fhem.de Sonstiges FHEM/24_NetIO230B.pm rudolfkoenig/orphan http://forum.fhem.de Sonstiges FHEM/30_HUEBridge.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/30_ENECSYSGW.pm akw http://forum.fhem.de Sonstige Systeme FHEM/31_HUEDevice.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/31_ENECSYSINV.pm akw http://forum.fhem.de Sonstige Systeme FHEM/31_LightScene.pm justme1968 http://forum.fhem.de Automatisierung FHEM/32_SYSSTAT.pm justme1968 http://forum.fhem.de Unterstuetzende Dienste FHEM/32_mailcheck.pm justme1968 http://forum.fhem.de Automatisierung