http://www.perlmonks.org?node_id=1021556

redriderjf87 has asked for the wisdom of the Perl Monks concerning the following question:

Hello, sorry in advance if this is not posted in the correct place or if it's not formatted correctly. Adapting the perl code below from Activestate to my local Kepware OPC server (and using the OPC Automation Wrapper), I am able to read an opc tag value, but writing a value via the OPC.pm Write function leaves the error

"0x80070057: The parameter is incorrect".

I looked over the perl module code and I'm not sure where a formatting or syntax issue could be happening. I've also had limited results searching for perl OPC information, besides the perl module's help file. In addition to the code I've supplied, I've also tried just passing a '0' value directly (which is all I'm trying to write actually to a single boolean tag) and get the same error.

I'd greatly appreciate any help or direction on how to write a tag value. Also, the write function is used near the end of the first code section which is my entire code. The 2nd code section is the part of the perl module referencing Write.

Thanks and let me know what other info I can provide, Justin

#!d:/win32apps/perl/bin/perl.exe -w # Copyright (c) 1999-2001 by Martin Tomes. All rights reserved. # This program is free software; you can redistribute it and/or modify + it # under the same terms as Perl itself. # Put the path to your perl interpreter above if you are using bash as + your # shell. # $Id: groups.pl,v 1.3 2001/01/11 10:40:40 martinto Exp $ # This example uses groups, group, items and item objects to get and s +et data # from the server. You will have to supply the OPC path names of some + items # and the server they are in for this to do anything. # It is assumed that you are using the FactorySoft OPC automation DLL +which # has the progid 'OPC.Automation'. use strict; use Win32::OLE::OPC qw(GetOPCServers $OPCCache $OPCDevice); #use Win32::OLE::OLE; #use Win32::OLE::Const; #use Win32::OLE::Enum; #use Win32::OLE::Lite; #use Win32::OLE::NLS; #use Win32::OLE::TypeInfo; #use Win32::OLE::Variant; use Sys::Hostname; my $server; my @items_read; my %items_write; if (hostname =~ /eurotherm.co.uk$/) { $server = 'Kepware.KEPServerEX.V5'; @items_read = ('Channel1.Device2.lockout_test'); %items_write = ('Channel1.Device2.lockout_test' => '0'); } else { # Put your values in here. $server = 'Kepware.KEPServerEX.V5'; @items_read = ('Channel1.Device2.lockout_test'); %items_write = ('Channel1.Device2.lockout_test' => '0'); } die "No server specified" unless ($server); die "No read items specified" unless (@items_read); die "No write items specified" unless (%items_write); my @available_servers = GetOPCServers('OPC.Automation'); my $found_server = 0; for my $name (@available_servers) { $found_server = 1 if (lc($name) eq lc($server)); } unless ($found_server) { print "Cannot find server $server, valid choices are: "; print join " ", @available_servers; print "\n"; exit 1; } # Connect to the selected server. my $opcintf = Win32::OLE::OPC->new('OPC.Automation', $server) or die "Failed to connect to $server: @!"; # Map the names given in items_read and items_write to item id's. foreach my $name (@items_read) { # Perl sets $name to be a reference to the element in @items_read so + you can # modify it like this. $name = $opcintf->GetItemIdFromName($name); } my %new_write; foreach my $key (keys %items_write) { my $itemid = $opcintf->GetItemIdFromName($key); $new_write{$itemid} = $items_write{$key}; } undef %items_write; %items_write = %new_write; undef %new_write; # Fetch the OPCGroups collection as an object. The object returned is + a # reference to a hash blessed into the Win32::OLE::OPC::Groups class. my $groups = $opcintf->OPCGroups; # Add an anonymous group. You can pass a string parameter to # Win32::OLE::OPC::Groups::Add(), in which case the new group takes on + the # name passed in. This returns a reference to a hash blessed into the # Win32::OLE::OPC::Group class. my $groupanon = $groups->Add(); # Get the items collection from the group object. This returns a refe +rence to # a hash blessed into the Win32::OLE::OPC::Items class. my $items = $groupanon->OPCItems; # Each item has an id which is assigned by the client. Generate an id + for # each item in @items_read. my @itemids; my $counter=0; for my $item (@items_read) { push @itemids, $counter++; } # This adds all the items in one call. $items->AddItems($#items_read+1, [@items_read], [@itemids]); # Now add the items to write. my $groupwrite = $groups->Add('write'); my $witems = $groupwrite->OPCItems; for my $item (keys(%items_write)) { $witems->AddItem($item, $counter++); } # Now show the properties of each of the above objects. sub PrintProperties { my $properties = shift; # Takes a reference to the properties. # Loop through the keys. for my $prop (keys %$properties) { if (defined($properties->{$prop})) { printf "%24s: %s\n", $prop, $properties->{$prop}; } else { printf "%24s: Undefined\n", $prop; } } } my %props; %props = $groups->Properties; print "OPCGroups Properties\n=================\n"; PrintProperties(\%props); print "\n"; %props = $groupanon->Properties; print "OPCGroup Properties\n=================\n"; PrintProperties(\%props); print "\n"; %props = $items->Properties; print "OPCItems (read) Properties\n=================\n"; PrintProperties(\%props); print "\n"; %props = $witems->Properties; print "OPCItems (write) Properties\n=================\n"; PrintProperties(\%props); print "\n"; # Now print out the item properties and values for the anonymous group +. #for (my $i = 1; $i <= ($#items_read+1); $i++) { # my $item = $items->Item($i); # if (defined($item)) { # %props = $item->Properties; # print "OPCItem Properties\n=================\n"; # PrintProperties(\%props); # print "OPCItem Data\n=================\n"; # PrintProperties($item->Read($OPCDevice)); # Reads from the device +. # print "\n"; # } #} # Now read, write and re-read these. $counter = 1; for my $item_name (keys(%items_write)) { my $item = $items->Item($counter++); # Assume they are in order! if (defined($item)) { # Read everything. %props = $item->Properties; print "OPCItem Properties\n=================\n"; PrintProperties(\%props); print "OPCItem Data\n=================\n"; PrintProperties($item->Read($OPCDevice)); # Reads from the device. my $curval = $item->Read($OPCCache)->{'Value'}; <b>$item->Write($items_write{$item_name});</b> sleep(2); my $newval = $item->Read($OPCDevice)->{'Value'}; printf "%24s: %s\n", 'New Value', $newval; <b>$item->Write($items_write{$item_name});</b> $newval = $item->Read($OPCDevice)->{'Value'}; printf "%24s: %s\n", 'Set back to', $newval; } } # Now get the server handle for each item and remove it from the items + list. my @server_handles; for (my $i = 1; $i <= ($#items_read+1); $i++) { my $item = $items->Item($i); if (defined($item)) { push @server_handles, $item->ServerHandle; } } $counter = 1; for my $item_name (keys(%items_write)) { my $item = $witems->Item($counter++); # Assume they are in order! if (defined($item)) { push @server_handles, $item->ServerHandle; } } $items->Remove(\@server_handles);
sub Write { my $self = shift; my $value = Variant(VT_VARIANT|VT_BYREF, shift); $self->{item}->Write($value); &Win32::OLE::OPC::_check_error("OPC::Item::Write " . $self->{_server +progid}); }

Replies are listed 'Best First'.
Re: Perl, OPC Tag Write
by Khen1950fx (Canon) on Mar 04, 2013 at 04:24 UTC
      Hmm, I did google the error code and my issue a lot, but apparently didn't see that. I'll take a look, thanks.
Re: Perl, OPC Tag Write
by Anonymous Monk on Mar 04, 2013 at 01:47 UTC

    I looked over the perl module code and I'm not sure where a formatting or syntax issue could be happening.

    What line triggers the error?

    What does the ole opc blah blah documentation says about that function? that error?

      Thanks for the reply. I'll take another look, but the documentation I could find didn't really get into the error codes at all. I should specify, this is what I've mainly been able to find: http://www.opcconnect.com/perl/OPC.html Thanks again

        this is what I've mainly been able to find: http://www.opcconnect.com/perl/OPC.html

        Um, that is just perl module , think of it as a webbrowser

        It (your program uses the module) makes some RPC calls to something microsoft ole , think of it as a website

        That microsoft ole thing (website) is throwing the error

        The perl module (webbrowser) doesn't know what it means, thats not its job, its just a middleman, it delivers the message to you

        The microsoft ole thing your program is communicating with, the ole server, knows what the error means

        You need to find documentation for this microsoft ole thing, its not a perl module, perl module is just translator

Re: Perl, OPC Tag Write
by Anonymous Monk on Mar 24, 2014 at 10:34 UTC
    Here is how to achieve Perl to OPC without so much coding: http://www.opclabs.com/products/quickopc/languages-and-tools/perl . Disclaimer: This is a self-promotion (QuickOPC library is a commercial product of ours).