mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 12:49:34 +00:00
S7: new module 44_S7*.pm added (charlie71)
git-svn-id: https://svn.fhem.de/fhem/trunk@10515 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
a62bbda796
commit
14d250024a
1143
fhem/FHEM/44_S7.pm
Normal file
1143
fhem/FHEM/44_S7.pm
Normal file
File diff suppressed because it is too large
Load Diff
448
fhem/FHEM/44_S7_ARead.pm
Normal file
448
fhem/FHEM/44_S7_ARead.pm
Normal file
@ -0,0 +1,448 @@
|
||||
# $Id$
|
||||
##############################################
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
#use Switch;
|
||||
require "44_S7_Client.pm";
|
||||
|
||||
my %gets = (
|
||||
|
||||
# "libnodaveversion" => ""
|
||||
);
|
||||
|
||||
sub _isfloat {
|
||||
my $val = shift;
|
||||
|
||||
# return $val =~ m/^\d+.\d+$/;
|
||||
return $val =~ m/^[-+]?\d*\.?\d*$/;
|
||||
|
||||
#[-+]?[0-9]*\.?[0-9]*
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_ARead_Initialize($) {
|
||||
my $hash = shift @_;
|
||||
|
||||
# Provider
|
||||
|
||||
# Consumer
|
||||
$hash->{Match} = "^AR";
|
||||
|
||||
$hash->{DefFn} = "S7_ARead_Define";
|
||||
$hash->{UndefFn} = "S7_ARead_Undef";
|
||||
$hash->{ParseFn} = "S7_ARead_Parse";
|
||||
|
||||
$hash->{AttrFn} = "S7_ARead_Attr";
|
||||
|
||||
$hash->{AttrList} = "IODev offset multiplicator " . $readingFnAttributes;
|
||||
|
||||
main::LoadModule("S7");
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_ARead_Define($$) {
|
||||
my ( $hash, $def ) = @_;
|
||||
my @a = split( "[ \t][ \t]*", $def );
|
||||
|
||||
my ( $name, $area, $DB, $start, $datatype );
|
||||
|
||||
$name = $a[0];
|
||||
$area = lc $a[2];
|
||||
$DB = $a[3];
|
||||
$start = $a[4];
|
||||
$datatype = lc $a[5];
|
||||
|
||||
if ( $area ne "inputs"
|
||||
&& $area ne "outputs"
|
||||
&& $area ne "flags"
|
||||
&& $area ne "db" )
|
||||
{
|
||||
my $msg =
|
||||
"wrong syntax: define <name> S7_ARead {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
if ( $datatype ne "u8"
|
||||
&& $datatype ne "s8"
|
||||
&& $datatype ne "u16"
|
||||
&& $datatype ne "s16"
|
||||
&& $datatype ne "u32"
|
||||
&& $datatype ne "s32"
|
||||
&& $datatype ne "float" )
|
||||
{
|
||||
my $msg =
|
||||
"wrong syntax: define <name> S7_ARead {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
$hash->{AREA} = $area;
|
||||
$hash->{DB} = $DB;
|
||||
$hash->{ADDRESS} = $start;
|
||||
$hash->{DATATYPE} = $datatype;
|
||||
|
||||
if ( $datatype eq "u16" || $datatype eq "s16" ) {
|
||||
$hash->{LENGTH} = 2;
|
||||
}
|
||||
elsif ( $datatype eq "u32" || $datatype eq "s32" || $datatype eq "float" ) {
|
||||
$hash->{LENGTH} = 4;
|
||||
}
|
||||
else {
|
||||
$hash->{LENGTH} = 1;
|
||||
}
|
||||
|
||||
my $ID = "$area $DB";
|
||||
|
||||
if ( !defined( $modules{S7_ARead}{defptr}{$ID} ) ) {
|
||||
my @b = ();
|
||||
push( @b, $hash );
|
||||
$modules{S7_ARead}{defptr}{$ID} = \@b;
|
||||
|
||||
}
|
||||
else {
|
||||
push( @{ $modules{S7_ARead}{defptr}{$ID} }, $hash );
|
||||
}
|
||||
|
||||
AssignIoPort($hash); # logisches modul an physikalisches binden !!!
|
||||
|
||||
$hash->{IODev}{dirty} = 1;
|
||||
Log3 $name, 4,
|
||||
"S7_ARead (" . $hash->{IODev}{NAME} . "): define $name Adress:$start";
|
||||
|
||||
return undef;
|
||||
}
|
||||
#####################################
|
||||
sub S7_ARead_Undef($$) {
|
||||
my ( $hash, $name ) = @_;
|
||||
|
||||
Log3 $name, 4,
|
||||
"S7_ARead ("
|
||||
. $hash->{IODev}{NAME}
|
||||
. "): undef "
|
||||
. $hash->{NAME}
|
||||
. " Adress:"
|
||||
. $hash->{ADDRESS};
|
||||
delete( $modules{S7_ARead}{defptr} );
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_ARead_Parse($$) {
|
||||
my ( $hash, $rmsg ) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
my @a = split( "[ \t][ \t]*", $rmsg );
|
||||
my @list;
|
||||
|
||||
my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer,
|
||||
$clientNames );
|
||||
|
||||
$area = lc $a[1];
|
||||
$DB = $a[2];
|
||||
$start = $a[3];
|
||||
$length = $a[4];
|
||||
$s7name = $a[5];
|
||||
$hexbuffer = $a[6];
|
||||
$clientNames = $a[7];
|
||||
|
||||
my $ID = "$area $DB";
|
||||
|
||||
Log3 $name, 5, "$name S7_ARead_Parse $rmsg";
|
||||
|
||||
my @clientList = split( ",", $clientNames );
|
||||
|
||||
if ( int(@clientList) > 0 ) {
|
||||
my @Writebuffer = unpack( "C" x $length,
|
||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
|
||||
#my $b = pack( "C" x $length, @Writebuffer );
|
||||
foreach my $clientName (@clientList) {
|
||||
|
||||
my $h = $defs{$clientName};
|
||||
|
||||
if ( $h->{TYPE} eq "S7_ARead"
|
||||
&& $start <= $h->{ADDRESS}
|
||||
&& $start + $length >= $h->{ADDRESS} + $h->{LENGTH} )
|
||||
{
|
||||
|
||||
my $n = $h->{NAME}; #damit die werte im client gesetzt werden!
|
||||
push( @list, $n );
|
||||
|
||||
#aktualisierung des wertes
|
||||
my $s = $h->{ADDRESS} - $start;
|
||||
my $myI;
|
||||
|
||||
if ( $h->{DATATYPE} eq "u8" ) {
|
||||
$myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s8" ) {
|
||||
$myI = $hash->{S7TCPClient}->ShortAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "u16" ) {
|
||||
$myI = $hash->{S7TCPClient}->WordAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s16" ) {
|
||||
$myI = $hash->{S7TCPClient}->IntegerAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "u32" ) {
|
||||
$myI = $hash->{S7TCPClient}->DWordAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s32" ) {
|
||||
$myI = $hash->{S7TCPClient}->DintAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "float" ) {
|
||||
$myI = $hash->{S7TCPClient}->FloatAt( \@Writebuffer, $s );
|
||||
}
|
||||
else {
|
||||
Log3 $name, 3,
|
||||
"$name S7_ARead: Parse unknown type : ("
|
||||
. $h->{DATATYPE} . ")";
|
||||
}
|
||||
|
||||
#now we need to correct the analog value by the parameters attribute and offset
|
||||
my $offset = 0;
|
||||
if ( defined( $main::attr{$n}{offset} ) ) {
|
||||
$offset = $main::attr{$n}{offset};
|
||||
}
|
||||
|
||||
my $multi = 1;
|
||||
if ( defined( $main::attr{$n}{multiplicator} ) ) {
|
||||
$multi = $main::attr{$n}{multiplicator};
|
||||
}
|
||||
|
||||
$myI = $myI * $multi + $offset;
|
||||
|
||||
#my $myResult;
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", $myI, 1 );
|
||||
|
||||
# main::readingsSingleUpdate($h,"value",$myResult, 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
Log3 $name, 3, "$name S7_ARead_Parse going the save way ";
|
||||
if ( defined( $modules{S7_ARead}{defptr}{$ID} ) ) {
|
||||
|
||||
foreach my $h ( @{ $modules{S7_ARead}{defptr}{$ID} } ) {
|
||||
if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
||||
&& $main::attr{ $h->{NAME} }{IODev} eq $name )
|
||||
{
|
||||
if ( $start <= $h->{ADDRESS}
|
||||
&& $start + $length >= $h->{ADDRESS} + $h->{LENGTH} )
|
||||
{
|
||||
|
||||
my $n =
|
||||
$h->{NAME}; #damit die werte im client gesetzt werden!
|
||||
push( @list, $n );
|
||||
|
||||
#aktualisierung des wertes
|
||||
|
||||
my @Writebuffer = unpack( "C" x $length,
|
||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
my $s = $h->{ADDRESS} - $start;
|
||||
|
||||
#my $b = pack( "C" x $length, @Writebuffer );
|
||||
my $myI;
|
||||
|
||||
if ( $h->{DATATYPE} eq "u8" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s8" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}
|
||||
->ShortAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "u16" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}->WordAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s16" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}
|
||||
->IntegerAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "u32" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}
|
||||
->DWordAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s32" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}->DintAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "float" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}
|
||||
->FloatAt( \@Writebuffer, $s );
|
||||
}
|
||||
else {
|
||||
Log3 $name, 3,
|
||||
"$name S7_ARead: Parse unknown type : ("
|
||||
. $h->{DATATYPE} . ")";
|
||||
}
|
||||
|
||||
#now we need to correct the analog value by the parameters attribute and offset
|
||||
my $offset = 0;
|
||||
if ( defined( $main::attr{$n}{offset} ) ) {
|
||||
$offset = $main::attr{$n}{offset};
|
||||
}
|
||||
|
||||
my $multi = 1;
|
||||
if ( defined( $main::attr{$n}{multiplicator} ) ) {
|
||||
$multi = $main::attr{$n}{multiplicator};
|
||||
}
|
||||
|
||||
$myI = $myI * $multi + $offset;
|
||||
|
||||
#my $myResult;
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", $myI, 1 );
|
||||
|
||||
# main::readingsSingleUpdate($h,"value",$myResult, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( int(@list) == 0 ) {
|
||||
Log3 $name, 6, "S7_ARead: Parse no client found ($name) ...";
|
||||
push( @list, "" );
|
||||
}
|
||||
|
||||
return @list;
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_ARead_Attr(@) {
|
||||
my ( $cmd, $name, $aName, $aVal ) = @_;
|
||||
|
||||
# $cmd can be "del" or "set"
|
||||
# $name is device name
|
||||
# aName and aVal are Attribute name and value
|
||||
my $hash = $defs{$name};
|
||||
if ( $cmd eq "set" ) {
|
||||
if ( $aName eq "offset" || $aName eq "multiplicator" ) {
|
||||
|
||||
if ( !_isfloat($aVal) ) {
|
||||
|
||||
Log3 $name, 3,
|
||||
"S7_ARead: Invalid $aName in attr $name $aName $aVal ($aVal is not a number): $@";
|
||||
return "Invalid $aName $aVal: $aVal is not a number";
|
||||
}
|
||||
|
||||
}
|
||||
elsif ( $aName eq "IODev" ) {
|
||||
if ( defined( $hash->{IODev} ) ) { #set old master device dirty
|
||||
$hash->{IODev}{dirty} = 1;
|
||||
}
|
||||
if ( defined( $defs{$aVal} ) ) { #set new master device dirty
|
||||
$defs{$aVal}{dirty} = 1;
|
||||
}
|
||||
Log3 $name, 4, "S7_ARead: IODev for $name is $aVal";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=pod
|
||||
=begin html
|
||||
|
||||
<a name="S7_ARead"></a>
|
||||
<h3>S7_ARead</h3>
|
||||
<ul>
|
||||
This module is a logical module of the physical module S7.<br />
|
||||
This module provides analog data (signed / unsigned integer Values).<br />
|
||||
Note: you have to configure a PLC reading at the physical module (S7) first.<br />
|
||||
<br />
|
||||
<br />
|
||||
<b>Define</b><br />
|
||||
<code>define <name> S7_ARead {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32}</code><br />
|
||||
|
||||
<ul>
|
||||
<li>inputs|outputs|flags|db … defines where to read.</li>
|
||||
<li>DB … Number of the DB</li>
|
||||
<li>start … start byte of the reading</li>
|
||||
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:
|
||||
<ul>
|
||||
<li>u8 …. unsigned 8 Bit integer</li>
|
||||
<li>s8 …. signed 8 Bit integer</li>
|
||||
<li>u16 …. unsigned 16 Bit integer</li>
|
||||
<li>s16 …. signed 16 Bit integer</li>
|
||||
<li>u32 …. unsigned 32 Bit integer</li>
|
||||
<li>s32 …. signed 32 Bit integer</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC reading of the physical module.</li>
|
||||
</ul>
|
||||
<br />
|
||||
<b>Attr</b><br />
|
||||
The following parameters are used to scale every reading
|
||||
<ul>
|
||||
<li>multiplicator</li>
|
||||
<li>offset</li>
|
||||
</ul>
|
||||
newValue = <multiplicator> * Value + <offset>
|
||||
</ul>
|
||||
=end html
|
||||
|
||||
=begin html_DE
|
||||
|
||||
<a name="S7_ARead"></a>
|
||||
<h3>S7_ARead</h3>
|
||||
<ul>
|
||||
This module is a logical module of the physical module S7.<br />
|
||||
This module provides analog data (signed / unsigned integer Values).<br />
|
||||
Note: you have to configure a PLC reading at the physical module (S7) first.<br />
|
||||
<br />
|
||||
<br />
|
||||
<b>Define</b><br />
|
||||
<code>define <name> S7_ARead {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32}</code><br />
|
||||
|
||||
<ul>
|
||||
<li>inputs|outputs|flags|db … defines where to read.</li>
|
||||
<li>DB … Number of the DB</li>
|
||||
<li>start … start byte of the reading</li>
|
||||
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:
|
||||
<ul>
|
||||
<li>u8 …. unsigned 8 Bit integer</li>
|
||||
<li>s8 …. signed 8 Bit integer</li>
|
||||
<li>u16 …. unsigned 16 Bit integer</li>
|
||||
<li>s16 …. signed 16 Bit integer</li>
|
||||
<li>u32 …. unsigned 32 Bit integer</li>
|
||||
<li>s32 …. signed 32 Bit integer</li>
|
||||
<li>float …. 4 byte float</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC reading of the physical module.</li>
|
||||
</ul>
|
||||
<b>Attr</b><br />
|
||||
The following parameters are used to scale every reading
|
||||
<ul>
|
||||
<li>multiplicator</li>
|
||||
<li>offset</li>
|
||||
</ul>
|
||||
newValue = <multiplicator> * Value + <offset>
|
||||
</ul>
|
||||
=end html_DE
|
||||
|
||||
=cut
|
||||
|
571
fhem/FHEM/44_S7_AWrite.pm
Normal file
571
fhem/FHEM/44_S7_AWrite.pm
Normal file
@ -0,0 +1,571 @@
|
||||
# $Id$
|
||||
##############################################
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
#use Switch;
|
||||
require "44_S7_Client.pm";
|
||||
|
||||
my %gets = (
|
||||
"reading" => "",
|
||||
"STATE" => ""
|
||||
);
|
||||
|
||||
#####################################
|
||||
sub S7_AWrite_Initialize($) {
|
||||
my $hash = shift @_;
|
||||
|
||||
# Consumer
|
||||
$hash->{Match} = "^AW";
|
||||
|
||||
$hash->{DefFn} = "S7_AWrite_Define";
|
||||
$hash->{UndefFn} = "S7_AWrite_Undef";
|
||||
|
||||
# $hash->{GetFn} = "S7_AWrite_Get";
|
||||
$hash->{SetFn} = "S7_AWrite_Set";
|
||||
$hash->{ParseFn} = "S7_AWrite_Parse";
|
||||
|
||||
$hash->{AttrFn} = "S7_AWrite_Attr";
|
||||
$hash->{AttrList} = "IODev " . $readingFnAttributes;
|
||||
|
||||
main::LoadModule("S7");
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_AWrite_Define($$) {
|
||||
my ( $hash, $def ) = @_;
|
||||
my @a = split( "[ \t][ \t]*", $def );
|
||||
|
||||
my ( $name, $area, $DB, $start, $datatype, $length );
|
||||
|
||||
$name = $a[0];
|
||||
$area = lc $a[2];
|
||||
$DB = $a[3];
|
||||
$start = $a[4];
|
||||
$datatype = lc $a[5];
|
||||
|
||||
Log3 $name, 5, "$name S7_AWrite_Define called";
|
||||
|
||||
if ( $area ne "inputs"
|
||||
&& $area ne "outputs"
|
||||
&& $area ne "flags"
|
||||
&& $area ne "db" )
|
||||
{
|
||||
my $msg =
|
||||
"$name wrong syntax: define <name> S7_AWrite {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}";
|
||||
|
||||
Log3 $name, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
if ( $datatype ne "u8"
|
||||
&& $datatype ne "s8"
|
||||
&& $datatype ne "u16"
|
||||
&& $datatype ne "s16"
|
||||
&& $datatype ne "u32"
|
||||
&& $datatype ne "s32"
|
||||
&& $datatype ne "float" )
|
||||
{
|
||||
my $msg =
|
||||
"$name wrong syntax: define <name> S7_AWrite {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}";
|
||||
|
||||
Log3 $name, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
AssignIoPort($hash); # logisches modul an physikalisches binden !!!
|
||||
|
||||
my $sname = $hash->{IODev}{NAME};
|
||||
|
||||
if ( $datatype eq "u16" || $datatype eq "s16" ) {
|
||||
$length = 2;
|
||||
}
|
||||
elsif ( $datatype eq "u32" || $datatype eq "s32" || $datatype eq "float" ) {
|
||||
$length = 4;
|
||||
}
|
||||
else {
|
||||
$length = 1;
|
||||
}
|
||||
|
||||
$hash->{AREA} = $area;
|
||||
$hash->{DB} = $DB;
|
||||
$hash->{ADDRESS} = $start;
|
||||
$hash->{DATATYPE} = $datatype;
|
||||
$hash->{LENGTH} = $length;
|
||||
|
||||
my $ID = "$area $DB";
|
||||
|
||||
if ( !defined( $modules{S7_AWrite}{defptr}{$ID} ) ) {
|
||||
my @b = ();
|
||||
push( @b, $hash );
|
||||
$modules{S7_AWrite}{defptr}{$ID} = \@b;
|
||||
|
||||
}
|
||||
else {
|
||||
push( @{ $modules{S7_AWrite}{defptr}{$ID} }, $hash );
|
||||
}
|
||||
|
||||
Log3 $name, 4,
|
||||
"S7_AWrite (" . $hash->{IODev}{NAME} . "): define $name Adress:$start";
|
||||
|
||||
$hash->{IODev}{dirty} = 1;
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_AWrite_Undef($$) {
|
||||
my ( $hash, $name ) = @_;
|
||||
|
||||
Log3 $name, 4,
|
||||
"S7_AWrite ("
|
||||
. $hash->{IODev}{NAME}
|
||||
. "): undef "
|
||||
. $hash->{NAME}
|
||||
. " Adress:"
|
||||
. $hash->{ADDRESS};
|
||||
delete( $modules{S7_AWrite}{defptr} );
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_AWrite_Set($@) {
|
||||
my ( $hash, @a ) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
Log3 $name, 5, "$name S7_AWrite_Set";
|
||||
|
||||
my $minValue;
|
||||
my $maxValue;
|
||||
|
||||
my $datatype = $hash->{DATATYPE};
|
||||
|
||||
#note I have used a SIEMENS Logo for testing here just the following range was supported.
|
||||
# $minValue = 0;
|
||||
# $maxValue = 32767;
|
||||
|
||||
if ( $datatype eq "u16" ) {
|
||||
$minValue = 0;
|
||||
$maxValue = 65535;
|
||||
}
|
||||
elsif ( $datatype eq "s16" ) {
|
||||
$minValue = -32768;
|
||||
$maxValue = 32767;
|
||||
}
|
||||
elsif ( $datatype eq "u32" ) {
|
||||
$minValue = 0;
|
||||
$maxValue = 4294967295;
|
||||
}
|
||||
elsif ( $datatype eq "s32" ) {
|
||||
$minValue = -2147483648;
|
||||
$maxValue = 2147483647;
|
||||
}
|
||||
elsif ( $datatype eq "float" ) {
|
||||
$minValue = -3.402823e38;
|
||||
$maxValue = 3.402823e38;
|
||||
}
|
||||
elsif ( $datatype eq "u8" ) {
|
||||
$minValue = 0;
|
||||
$maxValue = 255;
|
||||
}
|
||||
elsif ( $datatype eq "s8" ) {
|
||||
$minValue = -128;
|
||||
$maxValue = 127;
|
||||
}
|
||||
else { #should never happen
|
||||
$minValue = -1;
|
||||
$maxValue = 0;
|
||||
}
|
||||
|
||||
return "$name Need at least one parameter" if ( int(@a) < 2 );
|
||||
return " : " if ( $a[1] eq "?" );
|
||||
|
||||
if ( $a[1] ne int( $a[1] ) && $datatype ne "float" ) {
|
||||
return "$name You have to enter a numeric value: $minValue - $maxValue";
|
||||
}
|
||||
|
||||
my $newValue;
|
||||
if ( $datatype ne "float" ) {
|
||||
$newValue = int( $a[1] );
|
||||
}
|
||||
else {
|
||||
$newValue = $a[1];
|
||||
}
|
||||
|
||||
if ( $newValue < $minValue || $newValue > $maxValue ) {
|
||||
return "$name Out of range: $minValue - $maxValue";
|
||||
}
|
||||
|
||||
my $sname = $hash->{IODev}{NAME};
|
||||
|
||||
#find the rigth config
|
||||
my $area = $hash->{AREA};
|
||||
|
||||
my $length = $hash->{LENGTH};
|
||||
my $start = $hash->{ADDRESS};
|
||||
my $dbNR = $hash->{DB};
|
||||
my $shash = $defs{$sname};
|
||||
|
||||
if ( !defined( $shash->{S7TCPClient} ) ) {
|
||||
my $err = "$name S7_AWrite_Set: not connected to PLC ";
|
||||
Log3 $name, 3, $err;
|
||||
return $err;
|
||||
}
|
||||
|
||||
if ( $shash->{STATE} ne "connected to PLC" ) {
|
||||
my $err = "$name S7_AWrite_Set: not connected to PLC";
|
||||
Log3 $name, 3, $err;
|
||||
return $err;
|
||||
}
|
||||
|
||||
my $b;
|
||||
|
||||
my $WordLen;
|
||||
|
||||
if ( $datatype eq "u8" ) {
|
||||
$b = $shash->{S7TCPClient}->setByteAt( "X", 0, $newValue );
|
||||
$WordLen = &S7Client::S7WLByte;
|
||||
}
|
||||
elsif ( $datatype eq "s8" ) {
|
||||
$b = $shash->{S7TCPClient}->setShortAt( "X", 0, $newValue );
|
||||
$WordLen = &S7Client::S7WLByte;
|
||||
}
|
||||
elsif ( $datatype eq "u16" ) {
|
||||
$b = $shash->{S7TCPClient}->setWordAt( "XX", 0, $newValue );
|
||||
$WordLen = &S7Client::S7WLInt;
|
||||
|
||||
# $WordLen = &S7Client::S7WLWord;
|
||||
}
|
||||
elsif ( $datatype eq "s16" ) {
|
||||
$b = $shash->{S7TCPClient}->setIntegerAt( "XX", 0, $newValue );
|
||||
$WordLen = &S7Client::S7WLInt;
|
||||
|
||||
# $WordLen = &S7Client::S7WLWord;
|
||||
}
|
||||
elsif ( $datatype eq "u32" ) {
|
||||
$b = $shash->{S7TCPClient}->setDWordAt( "XXXX", 0, $newValue );
|
||||
$WordLen = &S7Client::S7WLDInt;
|
||||
|
||||
# $WordLen = &S7Client::S7WLDWord;
|
||||
}
|
||||
elsif ( $datatype eq "s32" ) {
|
||||
$b = $shash->{S7TCPClient}->setDintAt( "XXXX", 0, $newValue );
|
||||
$WordLen = &S7Client::S7WLDInt;
|
||||
|
||||
# $WordLen = &S7Client::S7WLDWord;
|
||||
}
|
||||
elsif ( $datatype eq "float" ) {
|
||||
$b = $shash->{S7TCPClient}->setFloatAt( "XXXX", 0, $newValue );
|
||||
$WordLen = &S7Client::S7WLReal;
|
||||
}
|
||||
else {
|
||||
my $err = "$name S7_AWrite: Parse unknown type : (" . $datatype . ")";
|
||||
Log3 $name, 3, $err;
|
||||
return $err;
|
||||
}
|
||||
|
||||
my $bss = join( ", ", unpack( "H2" x $length, $b ) );
|
||||
Log3 $name, 5, "$name S7_AWrite_Set: Write Bytes to PLC: $bss";
|
||||
|
||||
my $writeAreaIndex = S7_getAreaIndex4AreaName($area);
|
||||
return $writeAreaIndex if ( $writeAreaIndex ne int($writeAreaIndex) );
|
||||
|
||||
# my $res = S7_WriteBlockToPLC($shash,$writeAreaIndex,$dbNR,$start,$b);
|
||||
|
||||
my $res =
|
||||
S7_WriteToPLC( $shash, $writeAreaIndex, $dbNR, $start, $WordLen, $b );
|
||||
|
||||
if ( $res == 0 ) {
|
||||
main::readingsSingleUpdate( $hash, "state", $newValue, 1 );
|
||||
|
||||
}
|
||||
else {
|
||||
main::readingsSingleUpdate( $hash, "state", "", 1 );
|
||||
|
||||
}
|
||||
|
||||
return undef;
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_AWrite_Parse($$) {
|
||||
my ( $hash, $rmsg ) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my @list;
|
||||
my @a = split( "[ \t][ \t]*", $rmsg );
|
||||
|
||||
my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer,
|
||||
$clientNames );
|
||||
|
||||
$area = lc $a[1];
|
||||
$DB = $a[2];
|
||||
$start = $a[3];
|
||||
$length = $a[4];
|
||||
$s7name = $a[5];
|
||||
$hexbuffer = $a[6];
|
||||
$clientNames = $a[7];
|
||||
|
||||
my $ID = "$area $DB";
|
||||
|
||||
Log3 $name, 6, "$name S7_AWrite_Parse $rmsg";
|
||||
my @clientList = split( ",", $clientNames );
|
||||
|
||||
if ( int(@clientList) > 0 ) {
|
||||
my @Writebuffer = unpack( "C" x $length,
|
||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
|
||||
#my $b = pack( "C" x $length, @Writebuffer );
|
||||
foreach my $clientName (@clientList) {
|
||||
|
||||
my $h = $defs{$clientName};
|
||||
|
||||
if ( $h->{TYPE} eq "S7_AWrite"
|
||||
&& $start <= $h->{ADDRESS}
|
||||
&& $start + $length >= $h->{ADDRESS} + $h->{LENGTH} )
|
||||
{
|
||||
|
||||
my $n = $h->{NAME}; #damit die werte im client gesetzt werden!
|
||||
push( @list, $n );
|
||||
|
||||
#Aktualisierung des wertes
|
||||
|
||||
my $s = $h->{ADDRESS} - $start;
|
||||
my $myI;
|
||||
|
||||
if ( $h->{DATATYPE} eq "u8" ) {
|
||||
$myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s8" ) {
|
||||
$myI = $hash->{S7TCPClient}->ShortAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "u16" ) {
|
||||
$myI = $hash->{S7TCPClient}->WordAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s16" ) {
|
||||
$myI = $hash->{S7TCPClient}->IntegerAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "u32" ) {
|
||||
$myI = $hash->{S7TCPClient}->DWordAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s32" ) {
|
||||
$myI = $hash->{S7TCPClient}->DintAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "float" ) {
|
||||
$myI = $hash->{S7TCPClient}->FloatAt( \@Writebuffer, $s );
|
||||
}
|
||||
else {
|
||||
Log3 $name, 3, "$name S7_AWrite: Parse unknown type : ("
|
||||
. $h->{DATATYPE} . ")";
|
||||
}
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", $myI, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
Log3 $name, 3, "$name S7_AWrite_Parse going the save way ";
|
||||
if ( defined( $modules{S7_AWrite}{defptr}{$ID} ) ) {
|
||||
|
||||
foreach my $h ( @{ $modules{S7_AWrite}{defptr}{$ID} } ) {
|
||||
if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
||||
&& $main::attr{ $h->{NAME} }{IODev} eq $name )
|
||||
{
|
||||
if ( $start <= $h->{ADDRESS}
|
||||
&& $start + $length >= $h->{ADDRESS} + $h->{LENGTH} )
|
||||
{
|
||||
|
||||
my $n =
|
||||
$h->{NAME}; #damit die werte im client gesetzt werden!
|
||||
push( @list, $n );
|
||||
|
||||
#Aktualisierung des wertes
|
||||
|
||||
my @Writebuffer = unpack( "C" x $length,
|
||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
my $s = $h->{ADDRESS} - $start;
|
||||
|
||||
# my $b = pack( "C" x $length, @Writebuffer );
|
||||
my $myI;
|
||||
|
||||
if ( $h->{DATATYPE} eq "u8" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s8" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}
|
||||
->ShortAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "u16" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}->WordAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s16" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}
|
||||
->IntegerAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "u32" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}
|
||||
->DWordAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "s32" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}->DintAt( \@Writebuffer, $s );
|
||||
}
|
||||
elsif ( $h->{DATATYPE} eq "float" ) {
|
||||
$myI =
|
||||
$hash->{S7TCPClient}
|
||||
->FloatAt( \@Writebuffer, $s );
|
||||
}
|
||||
else {
|
||||
Log3 $name, 3,
|
||||
"$name S7_AWrite: Parse unknown type : ("
|
||||
. $h->{DATATYPE} . ")";
|
||||
}
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", $myI, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( int(@list) == 0 ) {
|
||||
Log3 $name, 6, "S7_AWrite: Parse no client found ($name) ...";
|
||||
push( @list, "" );
|
||||
|
||||
# return undef;
|
||||
}
|
||||
|
||||
return @list;
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_AWrite_Attr(@) {
|
||||
my ( $cmd, $name, $aName, $aVal ) = @_;
|
||||
|
||||
# $cmd can be "del" or "set"
|
||||
# $name is device name
|
||||
# aName and aVal are Attribute name and value
|
||||
my $hash = $defs{$name};
|
||||
if ( $cmd eq "set" ) {
|
||||
|
||||
if ( $aName eq "IODev" ) {
|
||||
if ( defined( $hash->{IODev} ) ) { #set old master device dirty
|
||||
$hash->{IODev}{dirty} = 1;
|
||||
}
|
||||
if ( defined( $defs{$aVal} ) ) { #set new master device dirty
|
||||
$defs{$aVal}{dirty} = 1;
|
||||
}
|
||||
Log3 $name, 4, "S7_AWrite: IODev for $name is $aVal";
|
||||
}
|
||||
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=pod
|
||||
=begin html
|
||||
|
||||
<a name="S7_AWrite"></a>
|
||||
<h3>S7_AWrite</h3>
|
||||
<ul>
|
||||
This module is a logical module of the physical module S7.<br />
|
||||
This module provides sending analog data (unsigned integer Values) to the PLC.<br />
|
||||
Note: you have to configure a PLC writing at the physical modul (S7) first.<br />
|
||||
<br />
|
||||
<b>Define</b>
|
||||
|
||||
<ul>
|
||||
<li><code>define <name> S7_AWrite {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}</code><br />
|
||||
|
||||
<ul>
|
||||
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
||||
<li>DB … Number of the DB</li>
|
||||
<li>start … start byte of the reading</li>
|
||||
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:
|
||||
<ul>
|
||||
<li>u8 …. unsigned 8 Bit integer</li>
|
||||
<li>s8 …. signed 8 Bit integer</li>
|
||||
<li>u16 …. unsigned 16 Bit integer</li>
|
||||
<li>s16 …. signed 16 Bit integer</li>
|
||||
<li>u32 …. unsigned 32 Bit integer</li>
|
||||
<li>s32 …. signed 32 Bit integer</li>
|
||||
<li>float …. 4 byte float</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC writing of the physical module.</li>
|
||||
</ul>
|
||||
<b>Set</b><br />
|
||||
|
||||
<ul>
|
||||
<li><code>set <name> S7_AWrite <value></code>
|
||||
|
||||
<ul>
|
||||
<li>value … an numeric value</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
=end html
|
||||
|
||||
=begin html_DE
|
||||
|
||||
<a name="S7_AWrite"></a>
|
||||
<h3>S7_AWrite</h3>
|
||||
<ul>
|
||||
This module is a logical module of the physical module S7.<br />
|
||||
This module provides sending analog data (unsigned integer Values) to the PLC.<br />
|
||||
Note: you have to configure a PLC writing at the physical modul (S7) first.<br />
|
||||
<br />
|
||||
<b>Define</b>
|
||||
|
||||
<ul>
|
||||
<li><code>define <name> S7_AWrite {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}</code><br />
|
||||
|
||||
<ul>
|
||||
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
||||
<li>DB … Number of the DB</li>
|
||||
<li>start … start byte of the reading</li>
|
||||
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:
|
||||
<ul>
|
||||
<li>u8 …. unsigned 8 Bit integer</li>
|
||||
<li>s8 …. signed 8 Bit integer</li>
|
||||
<li>u16 …. unsigned 16 Bit integer</li>
|
||||
<li>s16 …. signed 16 Bit integer</li>
|
||||
<li>u32 …. unsigned 32 Bit integer</li>
|
||||
<li>s32 …. signed 32 Bit integer</li>
|
||||
<li>float …. 4 byte float</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC writing of the physical module.</li>
|
||||
</ul>
|
||||
<b>Set</b><br />
|
||||
|
||||
<ul>
|
||||
<li><code>set <name> S7_AWrite <value></code>
|
||||
|
||||
<ul>
|
||||
<li>value … an numeric value</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</ul>
|
||||
|
||||
=end html_DE
|
||||
|
||||
=cut
|
1795
fhem/FHEM/44_S7_Client.pm
Normal file
1795
fhem/FHEM/44_S7_Client.pm
Normal file
File diff suppressed because it is too large
Load Diff
508
fhem/FHEM/44_S7_DRead.pm
Normal file
508
fhem/FHEM/44_S7_DRead.pm
Normal file
@ -0,0 +1,508 @@
|
||||
# $Id$
|
||||
##############################################
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
#use Switch;
|
||||
#use 44_S7_Client;
|
||||
|
||||
my %gets = (
|
||||
|
||||
# "libnodaveversion" => ""
|
||||
);
|
||||
|
||||
#####################################
|
||||
sub S7_DRead_Initialize($) {
|
||||
my $hash = shift @_;
|
||||
|
||||
# Provider
|
||||
|
||||
# Consumer
|
||||
$hash->{Match} = "^DR";
|
||||
|
||||
$hash->{DefFn} = "S7_DRead_Define";
|
||||
$hash->{UndefFn} = "S7_DRead_Undef";
|
||||
|
||||
$hash->{ParseFn} = "S7_DRead_Parse";
|
||||
|
||||
$hash->{AttrFn} = "S7_DRead_Attr";
|
||||
$hash->{AttrList} = "IODev " . $readingFnAttributes;
|
||||
|
||||
main::LoadModule("S7");
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_DRead_Define($$) {
|
||||
my ( $hash, $def ) = @_;
|
||||
my @a = split( "[ \t][ \t]*", $def );
|
||||
|
||||
my ( $name, $area, $DB, $start, $position );
|
||||
|
||||
$name = $a[0];
|
||||
|
||||
AssignIoPort($hash); # logisches modul an physikalisches binden !!!
|
||||
my $sname = $hash->{IODev}{NAME};
|
||||
|
||||
my $byte;
|
||||
my $bit;
|
||||
|
||||
if ( uc $a[2] =~ m/^[QIMN](\d*)/ ) {
|
||||
my $Offset;
|
||||
$area = "db";
|
||||
$DB = 0;
|
||||
my $startposition;
|
||||
|
||||
if ( uc $a[2] =~ m/^Q(\d*)/ ) {
|
||||
$startposition = 1;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
|
||||
$Offset = 942;
|
||||
}
|
||||
elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1064;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
}
|
||||
elsif ( uc $a[2] =~ m/^I(\d*)/ ) {
|
||||
$startposition = 1;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
|
||||
$Offset = 923;
|
||||
}
|
||||
elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1024;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
elsif ( uc $a[2] =~ m/^NI(\d*)/ ) {
|
||||
$startposition = 2;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1246;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
elsif ( uc $a[2] =~ m/^NQ(\d*)/ ) {
|
||||
$startposition = 2;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1390;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
elsif ( uc $a[2] =~ m/^M(\d*)/ ) {
|
||||
$startposition = 1;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
|
||||
$Offset = 948;
|
||||
}
|
||||
elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1104;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
$position =
|
||||
( $Offset * 8 ) + int( substr( $a[2], $startposition ) ) - 1;
|
||||
$byte = int( $position / 8 );
|
||||
$bit = ( $position % 8 );
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$area = lc $a[2];
|
||||
$DB = $a[3];
|
||||
$position = $a[4];
|
||||
|
||||
if ( $area ne "inputs"
|
||||
&& $area ne "outputs"
|
||||
&& $area ne "flags"
|
||||
&& $area ne "db" )
|
||||
{
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
my @address = split( /\./, $position );
|
||||
if ( int(@address) == 2 ) {
|
||||
$byte = $address[0];
|
||||
$bit = $address[1];
|
||||
}
|
||||
else {
|
||||
|
||||
$byte = int( $address[0] / 8 );
|
||||
$bit = ( $address[0] % 8 );
|
||||
}
|
||||
}
|
||||
|
||||
$hash->{AREA} = $area;
|
||||
$hash->{DB} = $DB;
|
||||
$hash->{POSITION} = ( $byte * 8 ) + $bit;
|
||||
$hash->{ADDRESS} = "$byte.$bit";
|
||||
$hash->{LENGTH} = 1;
|
||||
|
||||
my $ID = "$area $DB";
|
||||
|
||||
if ( !defined( $modules{S7_DRead}{defptr}{$ID} ) ) {
|
||||
my @b = ();
|
||||
push( @b, $hash );
|
||||
$modules{S7_DRead}{defptr}{$ID} = \@b;
|
||||
|
||||
}
|
||||
else {
|
||||
push( @{ $modules{S7_DRead}{defptr}{$ID} }, $hash );
|
||||
}
|
||||
|
||||
$hash->{IODev}{dirty} = 1;
|
||||
|
||||
Log3 $name, 4, "S7_DRead ($sname): define $name Adress:$byte.$bit";
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_DRead_Undef($$) {
|
||||
my ( $hash, $name ) = @_;
|
||||
|
||||
Log3 $name, 4,
|
||||
"S7_DRead ("
|
||||
. $hash->{IODev}{NAME}
|
||||
. "): undef "
|
||||
. $hash->{NAME}
|
||||
. " Adress:"
|
||||
. $hash->{ADDRESS};
|
||||
|
||||
delete( $modules{S7_DRead}{defptr} );
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_DRead_Parse_new($$) {
|
||||
my ( $hash, $rmsg ) = @_;
|
||||
my $name;
|
||||
|
||||
if ( defined( $hash->{NAME} ) ) {
|
||||
$name = $hash->{NAME};
|
||||
}
|
||||
else {
|
||||
Log3 undef, 2, "S7_DRead: Error ...";
|
||||
return undef;
|
||||
}
|
||||
|
||||
my @a = split( "[ \t][ \t]*", $rmsg );
|
||||
|
||||
my @list;
|
||||
|
||||
my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer );
|
||||
|
||||
$area = lc $a[1];
|
||||
$DB = $a[2];
|
||||
$start = $a[3];
|
||||
$length = $a[4];
|
||||
$s7name = $a[5];
|
||||
$hexbuffer = $a[6];
|
||||
my $ID = "$area $DB";
|
||||
|
||||
Log3 $name, 6, "$name S7_DRead_Parse $rmsg";
|
||||
|
||||
my @Writebuffer =
|
||||
unpack( "C" x $length, pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
|
||||
# my $b = pack( "C" x $length, @Writebuffer );
|
||||
|
||||
my $clientArray = $hash->{"Clients"};
|
||||
foreach my $h ( @{$clientArray} ) {
|
||||
if ( $start <= int( $h->{POSITION} / 8 )
|
||||
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
||||
{
|
||||
|
||||
#die Nachricht ist für den client
|
||||
|
||||
my $n = $h->{NAME}; #damit die werte im client gesetzt werden!
|
||||
push( @list, $n );
|
||||
|
||||
#aktualisierung des wertes
|
||||
|
||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||
my $myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
||||
|
||||
Log3 $name, 6, "$name S7_DRead_Parse update $n ";
|
||||
|
||||
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) > 0 ) {
|
||||
main::readingsSingleUpdate( $h, "state", "on", 1 );
|
||||
}
|
||||
else {
|
||||
main::readingsSingleUpdate( $h, "state", "off", 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( int(@list) == 0 ) {
|
||||
Log3 $name, 6, "S7_DRead: Parse no client found ($name) ...";
|
||||
push( @list, "" );
|
||||
}
|
||||
|
||||
return @list;
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_DRead_Parse($$) {
|
||||
my ( $hash, $rmsg ) = @_;
|
||||
my $name;
|
||||
|
||||
if ( defined( $hash->{NAME} ) ) {
|
||||
$name = $hash->{NAME};
|
||||
}
|
||||
else {
|
||||
Log3 undef, 2, "S7_DRead: Error ...";
|
||||
return undef;
|
||||
}
|
||||
|
||||
my @a = split( "[ \t][ \t]*", $rmsg );
|
||||
|
||||
my @list;
|
||||
|
||||
my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer,
|
||||
$clientNames );
|
||||
|
||||
$area = lc $a[1];
|
||||
$DB = $a[2];
|
||||
$start = $a[3];
|
||||
$length = $a[4];
|
||||
$s7name = $a[5];
|
||||
$hexbuffer = $a[6];
|
||||
$clientNames = $a[7];
|
||||
my $ID = "$area $DB";
|
||||
|
||||
Log3 $name, 5, "$name S7_DRead_Parse $rmsg";
|
||||
|
||||
# main::readingsBeginUpdate($h);
|
||||
# main::readingsBulkUpdate($h,"reading",$res,1);
|
||||
# main::readingsEndUpdate($h, 1);
|
||||
|
||||
my @clientList = split( ",", $clientNames );
|
||||
|
||||
if ( int(@clientList) > 0 ) {
|
||||
|
||||
my @Writebuffer = unpack( "C" x $length,
|
||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
|
||||
foreach my $clientName (@clientList) {
|
||||
|
||||
my $h = $defs{$clientName};
|
||||
|
||||
# if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
||||
# && $main::attr{ $h->{NAME} }{IODev} eq $name )
|
||||
# {
|
||||
|
||||
if ( $h->{TYPE} eq "S7_DRead"
|
||||
&& $start <= int( $h->{POSITION} / 8 )
|
||||
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
||||
{
|
||||
push( @list, $clientName )
|
||||
; #damit die werte im client gesetzt werden!
|
||||
|
||||
#aktualisierung des wertes
|
||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||
|
||||
my $myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
||||
|
||||
Log3 $name, 6, "$name S7_DRead_Parse update $clientName ";
|
||||
|
||||
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) > 0 ) {
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", "on", 1 );
|
||||
|
||||
}
|
||||
else {
|
||||
main::readingsSingleUpdate( $h, "state", "off", 1 );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
# }
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log3 $name, 3, "$name S7_DRead_Parse going the save way ";
|
||||
|
||||
if ( defined( $modules{S7_DRead}{defptr}{$ID} ) ) {
|
||||
|
||||
foreach my $h ( @{ $modules{S7_DRead}{defptr}{$ID} } ) {
|
||||
|
||||
if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
||||
&& $main::attr{ $h->{NAME} }{IODev} eq $name )
|
||||
{
|
||||
if ( $start <= int( $h->{POSITION} / 8 )
|
||||
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
||||
{
|
||||
|
||||
my $n =
|
||||
$h->{NAME}; #damit die werte im client gesetzt werden!
|
||||
push( @list, $n );
|
||||
|
||||
#aktualisierung des wertes
|
||||
my @Writebuffer = unpack( "C" x $length,
|
||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||
|
||||
#my $b = pack( "C" x $length, @Writebuffer );
|
||||
|
||||
my $myI =
|
||||
$hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
||||
|
||||
Log3 $name, 6, "$name S7_DRead_Parse update $n ";
|
||||
|
||||
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) >
|
||||
0 )
|
||||
{
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", "on", 1 );
|
||||
|
||||
}
|
||||
else {
|
||||
main::readingsSingleUpdate( $h, "state", "off", 1 );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( int(@list) == 0 ) {
|
||||
Log3 $name, 6, "S7_DRead: Parse no client found ($name) ...";
|
||||
push( @list, "" );
|
||||
}
|
||||
|
||||
return @list;
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_DRead_Attr(@) {
|
||||
my ( $cmd, $name, $aName, $aVal ) = @_;
|
||||
|
||||
# $cmd can be "del" or "set"
|
||||
# $name is device name
|
||||
# aName and aVal are Attribute name and value
|
||||
|
||||
my $hash = $defs{$name};
|
||||
|
||||
if ( $cmd eq "set" ) {
|
||||
|
||||
if ( $aName eq "IODev" ) {
|
||||
if ( defined( $hash->{IODev} ) ) { #set old master device dirty
|
||||
$hash->{IODev}{dirty} = 1;
|
||||
}
|
||||
if ( defined( $defs{$aVal} ) ) { #set new master device dirty
|
||||
$defs{$aVal}{dirty} = 1;
|
||||
}
|
||||
|
||||
Log3 $name, 4, "S7_DRead: IODev for $name is $aVal";
|
||||
}
|
||||
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
1;
|
||||
|
||||
=pod
|
||||
=begin html
|
||||
|
||||
<a name="S7_DRead"></a>
|
||||
<h3>S7_DRead</h3>
|
||||
<ul>
|
||||
This module is a logical module of the physical module S7.<br />
|
||||
This module provides digital data (ON/OFF).<br />
|
||||
Note: you have to configure a PLC reading at the physical modul (S7) first.<br />
|
||||
<br />
|
||||
<br />
|
||||
<b>Define</b>
|
||||
|
||||
<ul>
|
||||
<li><code>define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address></code>
|
||||
|
||||
<ul>
|
||||
<li>inputs|outputs|flags|db … defines where to read.</li>
|
||||
<li>DB … Number of the DB</li>
|
||||
<li>address … address you want to read. bit number to read. Example: 10.3</li>
|
||||
</ul>
|
||||
Note: the required memory area need to be with in the configured PLC reading of the physical module.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
=end html
|
||||
|
||||
=begin html_DE
|
||||
|
||||
<a name="S7_DRead"></a>
|
||||
<h3>S7_DRead</h3>
|
||||
<ul>
|
||||
This module is a logical module of the physical module S7.<br />
|
||||
This module provides digital data (ON/OFF).<br />
|
||||
Note: you have to configure a PLC reading at the physical modul (S7) first.<br />
|
||||
<br />
|
||||
<br />
|
||||
<b>Define</b>
|
||||
|
||||
<ul>
|
||||
<li><code>define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address></code>
|
||||
|
||||
<ul>
|
||||
<li>inputs|outputs|flags|db … defines where to read.</li>
|
||||
<li>DB … Number of the DB</li>
|
||||
<li>address … address you want to read. bit number to read. Example: 10.3</li>
|
||||
</ul>
|
||||
Note: the required memory area need to be with in the configured PLC reading of the physical module.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
=end html_DE
|
||||
|
||||
=cut
|
||||
|
546
fhem/FHEM/44_S7_DWrite.pm
Normal file
546
fhem/FHEM/44_S7_DWrite.pm
Normal file
@ -0,0 +1,546 @@
|
||||
# $Id$
|
||||
##############################################
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
#use Switch;
|
||||
|
||||
my %sets = (
|
||||
"on" => "",
|
||||
"off" => "",
|
||||
"toggle" => ""
|
||||
);
|
||||
|
||||
my %gets = (
|
||||
"reading" => "",
|
||||
"STATE" => ""
|
||||
);
|
||||
|
||||
#####################################
|
||||
sub S7_DWrite_Initialize($) {
|
||||
my $hash = shift @_;
|
||||
|
||||
# Provider
|
||||
|
||||
# Consumer
|
||||
$hash->{Match} = "^DW";
|
||||
|
||||
$hash->{DefFn} = "S7_DWrite_Define";
|
||||
$hash->{UndefFn} = "S7_DWrite_Undef";
|
||||
$hash->{SetFn} = "S7_DWrite_Set";
|
||||
|
||||
$hash->{ParseFn} = "S7_DWrite_Parse";
|
||||
|
||||
$hash->{AttrFn} = "S7_DWrite_Attr";
|
||||
$hash->{AttrList} = "IODev trigger_length " . $readingFnAttributes;
|
||||
|
||||
main::LoadModule("S7");
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_DWrite_Undef($$) {
|
||||
my ( $hash, $name ) = @_;
|
||||
RemoveInternalTimer($hash);
|
||||
Log3 $name, 4,
|
||||
"S7_DWrite ("
|
||||
. $hash->{IODev}{NAME}
|
||||
. "): undef "
|
||||
. $hash->{NAME}
|
||||
. " Adress:"
|
||||
. $hash->{ADDRESS};
|
||||
|
||||
delete( $modules{S7_DWrite}{defptr} );
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub S7_DWrite_Define($$) {
|
||||
my ( $hash, $def ) = @_;
|
||||
my @a = split( "[ \t][ \t]*", $def );
|
||||
|
||||
my ( $name, $area, $DB, $position );
|
||||
my $byte;
|
||||
my $bit;
|
||||
|
||||
$name = $a[0];
|
||||
Log3 $name, 5, "S7_DWrite_Define called";
|
||||
|
||||
AssignIoPort($hash); # logisches modul an physikalisches binden !!!
|
||||
|
||||
my $sname = $hash->{IODev}{NAME};
|
||||
|
||||
if ( uc $a[2] =~ m/^[QIMN](\d*)/ ) {
|
||||
$area = "db";
|
||||
$DB = 0;
|
||||
my $startposition;
|
||||
my $Offset;
|
||||
|
||||
if ( uc $a[2] =~ m/^Q(\d*)/ ) {
|
||||
$startposition = 1;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
|
||||
$Offset = 942;
|
||||
}
|
||||
elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1064;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DWrite {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DWrite {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
}
|
||||
elsif ( uc $a[2] =~ m/^I(\d*)/ ) {
|
||||
$startposition = 1;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
|
||||
$Offset = 923;
|
||||
}
|
||||
elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1024;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DWrite {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DWrite {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
elsif ( uc $a[2] =~ m/^NI(\d*)/ ) {
|
||||
$startposition = 2;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1246;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DWrite {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DWrite {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
elsif ( uc $a[2] =~ m/^NQ(\d*)/ ) {
|
||||
$startposition = 2;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1390;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DWrite {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DWrite {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
elsif ( uc $a[2] =~ m/^M(\d*)/ ) {
|
||||
$startposition = 1;
|
||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
|
||||
$Offset = 948;
|
||||
}
|
||||
elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||
$Offset = 1104;
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DWrite {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DWrite {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
else {
|
||||
my $msg =
|
||||
"wrong syntax : define <name> S7_DWrite {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DWrite {I|Q|M|NI|NQ}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
$position =
|
||||
( $Offset * 8 ) + int( substr( $a[2], $startposition ) ) - 1;
|
||||
$byte = int( $position / 8 );
|
||||
$bit = ( $position % 8 );
|
||||
|
||||
}
|
||||
else {
|
||||
$area = lc $a[2];
|
||||
$DB = $a[3];
|
||||
$position = $a[4];
|
||||
|
||||
if ( $area ne "inputs"
|
||||
&& $area ne "outputs"
|
||||
&& $area ne "flags"
|
||||
&& $area ne "db" )
|
||||
{
|
||||
my $msg =
|
||||
"wrong syntax: define <name> S7_DWrite {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DWrite {I|Q|M}1..24";
|
||||
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
my @address = split( /\./, $position );
|
||||
if ( int(@address) == 2 ) {
|
||||
$byte = $address[0];
|
||||
$bit = $address[1];
|
||||
}
|
||||
else {
|
||||
|
||||
$byte = int( $address[0] / 8 );
|
||||
$bit = ( $address[0] % 8 );
|
||||
}
|
||||
$position = ( $byte * 8 ) + $bit;
|
||||
}
|
||||
|
||||
$hash->{ADDRESS} = "$byte.$bit";
|
||||
|
||||
$hash->{AREA} = $area;
|
||||
$hash->{DB} = $DB;
|
||||
$hash->{LENGTH} = 1;
|
||||
$hash->{POSITION} = $position;
|
||||
|
||||
my $ID = "$area $DB";
|
||||
|
||||
if ( !defined( $modules{S7_DWrite}{defptr}{$ID} ) ) {
|
||||
my @b = ();
|
||||
push( @b, $hash );
|
||||
$modules{S7_DWrite}{defptr}{$ID} = \@b;
|
||||
|
||||
}
|
||||
else {
|
||||
push( @{ $modules{S7_DWrite}{defptr}{$ID} }, $hash );
|
||||
}
|
||||
|
||||
$hash->{IODev}{dirty} = 1;
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_DWrite_setABit($$) {
|
||||
my ( $hash, $newValue ) = @_;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
$newValue = lc $newValue;
|
||||
Log3 $name, 4, "S7_DWrite_setABit $newValue";
|
||||
|
||||
if ( $newValue ne "on" && $newValue ne "off" && $newValue ne "trigger" ) {
|
||||
return "Unknown argument $newValue, choose one of ON OFF TRIGGER";
|
||||
}
|
||||
|
||||
my $sname = $hash->{IODev}{NAME};
|
||||
my $position = $hash->{POSITION};
|
||||
my $area = $hash->{AREA};
|
||||
my $dbNR = $hash->{DB};
|
||||
my $shash = $defs{$sname};
|
||||
|
||||
my $writeAreaIndex = S7_getAreaIndex4AreaName($area);
|
||||
return $writeAreaIndex if ( $writeAreaIndex ne int($writeAreaIndex) );
|
||||
|
||||
my $b = 0;
|
||||
|
||||
if ( $newValue eq "on" || $newValue eq "trigger" ) {
|
||||
$b = 1;
|
||||
}
|
||||
|
||||
my $res = S7_WriteBitToPLC( $shash, $writeAreaIndex, $dbNR, $position, $b );
|
||||
|
||||
if ( $res == 0 ) {
|
||||
main::readingsSingleUpdate( $hash, "state", $newValue, 1 );
|
||||
}
|
||||
else {
|
||||
main::readingsSingleUpdate( $hash, "state", "", 1 );
|
||||
}
|
||||
|
||||
if ( $newValue eq "trigger" ) {
|
||||
|
||||
my $triggerLength = 1;
|
||||
if ( defined( $main::attr{$name}{trigger_length} ) ) {
|
||||
$triggerLength = $main::attr{$name}{trigger_length};
|
||||
}
|
||||
|
||||
InternalTimer( gettimeofday() + $triggerLength,
|
||||
"S7_DWrite_SwitchOff", $hash, 1 );
|
||||
}
|
||||
|
||||
return undef;
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_DWrite_Set(@) {
|
||||
my ( $hash, @a ) = @_;
|
||||
|
||||
return "Need at least one parameter" if ( int(@a) < 2 );
|
||||
return S7_DWrite_setABit( $hash, $a[1] );
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_DWrite_SwitchOff($) {
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
Log3 $name, 4, "S7_DWrite: GetUpdate called ...";
|
||||
|
||||
return S7_DWrite_setABit( $hash, "off" );
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
|
||||
sub S7_DWrite_Parse($$) {
|
||||
my ( $hash, $rmsg ) = @_;
|
||||
my $name;
|
||||
|
||||
if ( defined( $hash->{NAME} ) ) {
|
||||
$name = $hash->{NAME};
|
||||
}
|
||||
else {
|
||||
$name = "dummy";
|
||||
Log3 undef, 2, "S7_DWrite_Parse: Error ...";
|
||||
return undef;
|
||||
}
|
||||
|
||||
my @a = split( "[ \t][ \t]*", $rmsg );
|
||||
my @list;
|
||||
|
||||
my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer,
|
||||
$clientNames );
|
||||
|
||||
$area = lc $a[1];
|
||||
$DB = $a[2];
|
||||
$start = $a[3];
|
||||
$length = $a[4];
|
||||
$s7name = $a[5];
|
||||
$hexbuffer = $a[6];
|
||||
$clientNames = $a[7];
|
||||
|
||||
my $ID = "$area $DB";
|
||||
|
||||
Log3 $name, 6, "$name S7_DWrite_Parse $rmsg";
|
||||
my @clientList = split( ",", $clientNames );
|
||||
|
||||
if ( int(@clientList) > 0 ) {
|
||||
my @Writebuffer = unpack( "C" x $length,
|
||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
# my $b = pack( "C" x $length, @Writebuffer );
|
||||
foreach my $clientName (@clientList) {
|
||||
|
||||
my $h = $defs{$clientName};
|
||||
|
||||
# if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
||||
# && $main::attr{ $h->{NAME} }{IODev} eq $name )
|
||||
# {
|
||||
|
||||
if ( $h->{TYPE} eq "S7_DWrite"
|
||||
&& $start <= int( $h->{POSITION} / 8 )
|
||||
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
||||
{
|
||||
push( @list, $clientName )
|
||||
; #damit die werte im client gesetzt werden!
|
||||
|
||||
#aktualisierung des wertes
|
||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||
|
||||
my $myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
||||
|
||||
Log3 $name, 5, "$name S7_DWrite_Parse update $clientName ";
|
||||
|
||||
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) > 0 ) {
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", "on", 1 );
|
||||
|
||||
}
|
||||
else {
|
||||
main::readingsSingleUpdate( $h, "state", "off", 1 );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
# }
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log3 $name, 3, "$name S7_DWrite_Parse going the save way ";
|
||||
|
||||
if ( defined( $modules{S7_DWrite}{defptr}{$ID} ) ) {
|
||||
|
||||
foreach my $h ( @{ $modules{S7_DWrite}{defptr}{$ID} } ) {
|
||||
if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
||||
&& $main::attr{ $h->{NAME} }{IODev} eq $name )
|
||||
{
|
||||
if ( $start <= int( $h->{POSITION} / 8 )
|
||||
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
||||
{
|
||||
|
||||
my $n =
|
||||
$h->{NAME}; #damit die werte im client gesetzt werden!
|
||||
push( @list, $n );
|
||||
|
||||
#aktualisierung des wertes
|
||||
my @Writebuffer = unpack( "C" x $length,
|
||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||
# my $b = pack( "C" x $length, @Writebuffer );
|
||||
|
||||
my $myI = $hash->{S7TCPClient}->ByteAt(\@Writebuffer, $s );
|
||||
|
||||
Log3 $name, 6, "$name S7_DWrite_Parse update $n ";
|
||||
|
||||
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) >
|
||||
0 )
|
||||
{
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", "on", 1 );
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
main::readingsSingleUpdate( $h, "state", "off", 1 );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( int(@list) == 0 ) {
|
||||
Log3 $name, 6, "S7_DWrite: Parse no client found ($name) ...";
|
||||
push( @list, "" );
|
||||
}
|
||||
|
||||
return @list;
|
||||
|
||||
}
|
||||
#####################################
|
||||
|
||||
sub S7_DWrite_Attr(@) {
|
||||
my ( $cmd, $name, $aName, $aVal ) = @_;
|
||||
|
||||
# $cmd can be "del" or "set"
|
||||
# $name is device name
|
||||
# aName and aVal are Attribute name and value
|
||||
my $hash = $defs{$name};
|
||||
if ( $cmd eq "set" ) {
|
||||
if ( $aName eq "trigger_length" ) {
|
||||
if ( $aVal ne int($aVal) ) {
|
||||
Log3 $name, 3,
|
||||
"S7_DWrite: Invalid $aName in attr $name $aName ($aVal is not a number): $@";
|
||||
return "Invalid $aName : $aVal is not a number";
|
||||
}
|
||||
|
||||
}
|
||||
elsif ( $aName eq "IODev" ) {
|
||||
Log3 $name, 4, "S7_DWrite: IODev for $name is $aVal";
|
||||
$hash->{IODev}{dirty} = 1;
|
||||
}
|
||||
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=pod
|
||||
=begin html
|
||||
|
||||
<a name="S7_DWrite"></a>
|
||||
<h3>S7_DWrite</h3>
|
||||
<ul>
|
||||
This module is a logical module of the physical module S7.<br />
|
||||
This module is used to set/unset a Bit in ad DB of the PLC.<br />
|
||||
Note: you have to configure a PLC writing at the physical modul (S7) first.<br />
|
||||
<br />
|
||||
<b>Define</b>
|
||||
|
||||
<ul>
|
||||
<li><code>define <name> S7_DWrite {db} <DB> <address></code>
|
||||
|
||||
<ul>
|
||||
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
||||
<li>DB … Number of the DB</li>
|
||||
<li>address … address you want to write. bit number to read. Example: 10.6</li>
|
||||
</ul>
|
||||
Note: the required memory area need to be with in the configured PLC reading of the physical module. <b>Set</b>
|
||||
|
||||
<ul>
|
||||
<li><code>set <name> S7_AWrite {ON|OFF|TRIGGER};</code></li>
|
||||
<br />
|
||||
|
||||
<li> </li>
|
||||
<li> </li>
|
||||
</ul>
|
||||
Note: TRIGGER sets the bit for 1s to ON than it will set to OFF.</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Attr</b><br />
|
||||
The following parameters are used to scale every reading</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<ul>
|
||||
<li>trigger_length ... sets the on-time of a trigger</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
=end html
|
||||
|
||||
=begin html_DE
|
||||
|
||||
<a name="S7_DWrite"></a>
|
||||
<h3>S7_DWrite</h3>
|
||||
<ul>
|
||||
This module is a logical module of the physical module S7.<br />
|
||||
This module is used to set/unset a Bit in ad DB of the PLC.<br />
|
||||
Note: you have to configure a PLC writing at the physical modul (S7) first.<br />
|
||||
<br />
|
||||
<br />
|
||||
<b>Define</b>
|
||||
|
||||
<ul>
|
||||
<li><code>define <name> S7_DWrite {db} <DB> <position></code>
|
||||
|
||||
<ul>
|
||||
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
||||
<li>DB … Number of the DB</li>
|
||||
<li>address … address you want to write. bit number to read. Example: 10.6</li>
|
||||
</ul>
|
||||
Note: the required memory area need to be with in the configured PLC reading of the physical module.</li>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<li> </li>
|
||||
</ul>
|
||||
<b>Set</b>
|
||||
|
||||
<ul>
|
||||
<li><code>set <name> S7_AWrite {ON|OFF|TRIGGER};</code><br />
|
||||
Note: TRIGGER sets the bit for 1s to ON than it will set to OFF.</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Attr</b><br />
|
||||
The following parameters are used to scale every reading</p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<ul>
|
||||
<li>trigger_length ... sets the on-time of a trigger</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
=end html_DE
|
||||
|
||||
=cut
|
||||
|
Loading…
Reference in New Issue
Block a user