I use PERL and it’s Modbus modules to read out a Siemens S7 PLC which is doing our Water Treatment of our town.
Works like a charm and is ultra robust. So if one doesn’t like Python, which i also use to read other small PLC’s, PERL is also a good lightweight alternative.
In addition what Bill Thomson said the Siemens is doing it with reversed registers which is odd to know.
I see the Mod TCP is really easy to use and I personally would prefer a TCP Modbus device over a RTU. In my case I use 2-wire DSL modems to do a p2p connection between two water reservoirs 1.8km distance. On the main reservoir I connect from the Workstation via these DSL modems to the siemens over normal ethernet TCP connection and it’s stable and did not have any failures for over a year. The smaller RTU PLCs, like the SDM630 power meter do have some oddities with the USB RS485 adapter.
Here’s the PERL script to connect to a Modbus TCP device:
#!/usr/bin/perl
use Device::Modbus::Client;
use Device::Modbus::TCP::Client;
use strict;
use warnings;
use v5.10;
use LWP::Simple;
use DBI;
my $port = "503";
my $remote = IO::Socket::INET->new(
Proto => "tcp",
PeerAddr => "192.168.1.5",
PeerPort => $port,
Timeout => 2,
);
my $client = Device::Modbus::TCP::Client->new(
host => '192.168.1.5',
port => 503,
);
my @req = (
# Word oriented
$client->read_holding_registers(
address => 0,
quantity => 50
)
);
$client->send_request($req[0]) || die "Send error: $!";
$response = $client->receive_response;
@values = @{ $response->values };
and here is the part to actually reverse the floating point values of the registers. In this case, I wanted to get the height of the water level in the reservoir. Siemens stores these values in reverse order:
$NiveauReservoir = unpack 'f', pack 'v2', $values[22], $values[21];
say sprintf "Niveau_Reservoir_Meter:%f", $NiveauReservoir;
The unpack
was the key to get the data back into the correct order 
I’m posting this because it took me a few days to find this information, and maybe others will benefit from this knowledge 