Hauptmenü

Need help modbus specific

Begonnen von smarthacker, 27 Januar 2019, 18:05:35

Vorheriges Thema - Nächstes Thema

smarthacker

Hi All,

I am building writing a custom module to read values from 2 different devices both device communicate over Modbus TCP.

But the problem is both devices have different IP and port I need to write them into one module since I need to achieve PID regulation between these two devices. I need to set values based on the value of the first device.
Here are my conf and module code.

My question is for the first device I want to read only "h40499"  and for the second device only "h1000" and "h1001".

But with the current config, I am getting the temperature, power and power meter values for both devices. I want to separate them.
Once I call the ModbusLD_Initialize it just takes the control to parent module.

can someone please help me with this.

I am following the guidelines from the following link
https://wiki.fhem.de/wiki/DevelopmentModuleIntro

defmod powermeter ACT 1 1 192.168.101.1:502 TCP
define serial dummy
set serial 1438503

def powermeter1 ACT 1 1 192.168.101.1:503 TCP




package  main ;
use strict ;
use warnings ;
use Data::Dumper;

my %parseInfo = (
    "h40499"  =>  {
        reading => "powermeter",
        poll => 1,
        unpack => 'N',
        len => 2,
        expr => 'int($val - Value(\'serial\')'
    },
    "h1000"  =>  {
        reading => "power",
        poll => 1,
    },
    "h1001"  =>  {
        reading => "tempreture",
        poll => 1,
        expr => '$val/10',
        format => '%.1f'
    },
);

sub ACT_Initialize ($)  {
    my ($modHash) = @_;

    LoadModule "Modbus";
    require "$attr{global}{modpath}/FHEM/DevIo.pm";

    $modHash->{parseInfo}  = \%parseInfo;

    ModbusLD_Initialize($modHash);
}

sub ACT_Define ($$) {
    my  ( $hash,$def)  =  @_ ;
    print Dumper @_;
}

1;

smarthacker

can anyone please help me or port me to correct forum/person

Beta-User

According to MAINTAINER.txt modbus is located in the "Sonstiges" part of the forum.

But in general: what restrictions with existing FHEM modules motivate you to write one of your own?- dummy or readingsProxy/ReadingsGroup to combine information coming from the two Modbus-Devices?
- PID20 (see Automatisierung) to do the logic part to manipulate whatever actor?

Perhaps you should provide some more info what kind of information is taken from whatever machine and transferred to which other one and move this post to the english corner? There are a lot of very experienced users having a regular look also at that part of the forum.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

smarthacker

Hi,
Thanks for your reply.
Your questions:-
what restrictions with existing FHEM modules motivate you to write one of your own?- dummy or readingsProxy/ReadingsGroup to combine information coming from the two Modbus-Devices?

First yes for dummy thing I did and I am not sure how to write sub in conf it self and how to read access the realtime value fetch by fhem from two devices.
do you have idea on this and I am moving this post to english corner as mention.
Thanks again.

Beta-User

Sorry, I'm not sure if I got you right:

Your setup could be:

Modbus1: MODBUS device for first IP => has readings named ValueA01 to ValueA10
Modbus2: MODBUS device for second IP => has readings named ValueB01 to ValueB10

To sort that in a better visible way, you could use ReadingsGroup. Example.

If you really need to have them in the same logical place, use "notify" and (one) "dummy". Either use "setList" attribute to add ValueA01 to ValueB10 to this "dummy" or the "setreading" command (see commandref, as for most of the stuff I try to explain; you can use different naming conventions on the notification part and the resulting set(reading) command).

You could also use e.g. "notify" to transfer (modified if necessary) input info from Modbus1 to any variable on Modbus2...

Imo this is relatively abstract, so I'd suggest you try to define 2 modbus devices and add "list" of each of them here and explain what values you need in the end.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

smarthacker

You got me right Sir.
I believe your explanation will work for what I am intending to do.
But will config allow me to write some custom logic in it. For notify what I can use equivalent in module to fetch values ? any idea. 

Beta-User

Custom logic is myUtils code IMO. Search esp. the cref for that.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

smarthacker

All right sure.Thank for your help. I will update you with how it goes.It really helps.Thanks again.

Beta-User

One remark: As already mentionned, there's also a module handling PID logics. You might find it helpful, see commandref of PID20.

Good success!
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

smarthacker

Hi Stefan Strobel,

I will try to explain in detail.

I have 2 devices, Device A and Device B. Both can communicate MODBUS over TCP.

    Device A :- Device A has 16 bit + 16 bit values in register h40499 and h40500
              Combined 32 bit value is power and serial number.
                Outof which I need power value which I obtain using
                int($val^(2**32- 1)) - Value('serial')
               
               
    Device B :- Device B has power and temperature. in register h1000 and h1001
                Both can be obtained directly just need to divide the temperature by 10 while displaying.


    Wants to achieve:-
                I want to set values in Device A this value will be calculated using the PID regulation.
                When the temperature in Device B falls below 0.

        My both device is on different IP I want to read from one device A and do the calculation and set value in other device B.
        Using the following conf I am able to read and compute values based on the formula. But for the logic, I decided to start with writing the module but I am sure the conf itself has the power to achieve what I want to achieve.
        In last post @Beta-User help me pointing to notify I tried in module but control do not comes to the sub DEVICEA_Notify I defined.

Here is my current conf value reading logic didn't work.

define DEVICEA ModbusAttr 1 1 192.168.101.1:503 TCP
attr DEVICEA userattr obj-h40499-expr obj-h40499-len obj-h40499-poll obj-h40499-reading obj-h40499-unpack
attr DEVICEA obj-h40499-len 2
attr DEVICEA obj-h40499-poll 1
attr DEVICEA obj-h40499-set 1
attr DEVICEA obj-h40499-expr int($val^(2**32- 1)) - Value('serial')
attr DEVICEA obj-h40499-reading power_meter
attr DEVICEA obj-h40499-unpack N
attr DEVICEA obj-h40499-format %d Watt
attr DEVICEA room 1
define serial dummy
set serial 1438503


define DEVICEB ModbusAttr 1 1 192.168.101.1:502 TCP
# attr DEVICEB obj-h1000-expr $val
attr DEVICEB obj-h1000-expr Value('current_temp_val')
attr DEVICEB obj-h1000-poll 1
attr DEVICEB obj-h1000-reading Power
attr DEVICEB obj-h1001-expr $val / 10
attr DEVICEB obj-h1001-poll 1
attr DEVICEB obj-h1001-reading Tempreture
attr DEVICEB obj-h1001-format %.1f
define serial current_temp_val
set current_temp_val ReadingsVal($name,"power_meter",0)

define set_val to notify (DEVICEA) {
    my $temp_val = Value("current_temp_val");
    if($temp_val < 0) {
        fhem ("set DEVICEA power_meter 20");
        #trying to set 20 for test
        #will need to calculate the 20 by doing PID regulation
    }
}





My Module file I started.


###################### FILe 98_DEVICEA.pm #########################

package  main;
use strict;
use warnings;
use Data::Dumper;

sub DEVICEA_Initialize($);
sub DEVICEA_Define($$);
sub DEVICEA_Notify($);

my %parseInfo = (
    "h40499"  =>  {
        reading => "powermeter",   # name of the reading for this value
        poll => 1,
        unpack => 'N',
        len => 2,
        set => 1,
        expr => 'int($val^(2**32- 1)) - Value(\'serial\')'
    },
    "h1000"  =>  {
        reading => "power",
        poll => 1,
    },
    "h1001"  =>  {
        reading => "tempreture",
        poll => 1,
        expr => '$val/10',
        format => '%.1f'
    },
);

sub
DEVICEA_Initialize($)
{
    my ($hash) = @_;

    require "$attr{global}{modpath}/FHEM/98_Modbus.pm";
    require "$attr{global}{modpath}/FHEM/DevIo.pm";
    $hash->{GetFn}    = "DEVICEA_Get";
    $hash->{SetFn}    = "DEVICEA_Set";
    $hash->{InitFn}   = "DEVICEA_Init";
    $hash->{DefFn}    = "DEVICEA_Define";
    $hash->{UndefFn}  = "DEVICEA_Undef";
    $hash->{ParseFn}  = "DEVICEA_Parse";
    $hash->{NotifyFn} = "DEVICEA_Notify";
    $hash->{AttrFn}   = "DEVICEA_Attr";
  $hash->{parseInfo}  = \%parseInfo; # defines registers for this Modbus Defive
    # $hash->{deviceInfo} = \%deviceInfo; # defines properties of the device like
  ModbusLD_Initialize($hash); # Generic function of the Modbus module does the rest

}

###################################

sub DEVICEA_Notify ($) {
    print Dumper @_;
    my $name     = $_[0]->{NAME};

}

1;


I not aware of most of the FHEM part whatever I have achieved so far is with the help of wiki provided, forums help and referring to existing code. I am very much thankful to this community.
Given this fact I might be on wrong track too perhaps,  there is a very easy way to achieve this.


  • I want to read a real-time value from deviceA
  • based on that value I want to do a PID regulation that will decide the output value
  • and would like to set the value if the temperature in deviceB is less than  0 or negative
  • as pointed I am trying to learn about the PID20  module in fhem

So far to test I am using the ananas Modbus simulator. Using Ubuntu 16.04.
I hope you can help me and thanks in advance.

StefanStrobel

Hello,

if you were successful reading the values via Modbus-TCP then you have already mastered most of the challenges.

One more hint regarding registers that have to be combined to calculate a final value:
You might get into trouble when e.g. h40499 is read and then the device changes the values and then 40500 is read. Then the two values are not consistant anymore.
So you have to make sure that both registers are combined into one Modbus-request and are retrieved at the same time.
To resolve this you can define an object with length 2 and an unpack code that creates two values.
I described this in post #51 at https://forum.fhem.de/index.php/topic,80767.45.html

As far as the further processing is concerned, there are two options:

Either you do this periodically and read the input values from other defined Fhem-devices with the function ReadingsVal every e.g. 2 seconds and then you do your calculations and actions based on it
(define FirstModbusDevice Modbus ..., define SecondModbusDevice Modbus ..., define Calculation At ...)

Or you react on the change of a reading which creates an internal event in Fhem. To do this you can define a notify in the fhem configuration (you don't need to write your own module to do this) - see https://fhem.de/commandref.html#notify

inside At- or Notify-Fhem-devices you can still use Perl code, but you don't need to write a module!

Or if you really want to writ your own module then you need to dig deeper into Perl and how Fhem works internally.
But also in this case I would not try to write one module that does it all and combines Modbus reading with your PID stuff. If you try this then you will also need to understand how 98_Modbus.pm works internally...
Instead you can try to just write your calculations, NotifyFn and so on in a module.

By the way the reson why your Notify function didn't see anything is that you assign it first with $hash->{NotifyFn} = "DEVICEA_Notify" but then you call ModbusLD_Initialize($hash) which overwrites it again.
98_Modbus.pm is not meant to be used in a custom module that does many other things. It is mainly meant to be a basis for special modules that support one specific modbus device.

I hope this helps a bit further.

regards,
   Stefan



smarthacker

Hi Stefan,

Thank you so much for this detailed explanation it really helped me understand the things in more depth.
After your reply I understood the concerns about the new module creation and currently working the notify block in conf itself.