Use data store data in other python module

691 views
Skip to first unread message

Mikael Ljunggren

unread,
Dec 1, 2014, 3:25:44 PM12/1/14
to pymo...@googlegroups.com
Hi all,

I have started an asyncronus modbus server in an RPI to receive data from a PLC over a GPRS link

Everything works fine and i see the debug data arriving to the RPI and all data is correct

However, I would like to use the received data to decode it (inputs on/off etc, analoge temp values etc) to populate a dashboard, perhaps push it down to a MySQL database

But here I'm stuck, I should also mention that I am a newbie in Python but trying hard to learn

Would be very grateful for any tips or if someone could point me in the right direction

Thanks

Mikael

Agustin Gimeno

unread,
Dec 2, 2014, 8:52:29 AM12/2/14
to pymo...@googlegroups.com

Mikael Ljunggren

unread,
Dec 3, 2014, 1:52:22 PM12/3/14
to pymo...@googlegroups.com
Thanks Agustin!

I will try that as soon as I have the possibility

Regards,
Mikael

Mikael Ljunggren

unread,
Dec 15, 2014, 3:38:47 PM12/15/14
to pymo...@googlegroups.com
Hi again,

Now I have tried to use the Updating Server example but still stuck as in glue

My PLC sends (pushes) data with a certain frequency to the ModBus Server and all that data pops up in the terminal window from the debug function

However, this data doesn't seem to end up in the data store and if I use the Updating Server example and try to access the data store there is nothing there!

The debug data from the PLC looks like this:

DEBUG:pymodbus.server.async:Client Connected [IPv4Address(TCP, '192.168.0.50', 5001)]
DEBUG
:pymodbus.server.async:0x0 0x3 0x0 0x0 0x0 0xa 0x1 0x8b 0x7 0x0 0x1 0x1 0xe2 0x2 0x1 0x8
DEBUG
:pymodbus.transaction:0x0 0x3 0x0 0x0 0x0 0xa 0x1 0x8b 0x7 0x0 0x1 0x1 0xe2 0x2 0x1 0x8
DEBUG
:pymodbus.factory:Factory Request[139]
DEBUG
:pymodbus.server.async:send: 000300000003018b01

And I want to access that data and decode the string to tell if an input is high or low etc

Is it possible to do that and in that case how?

Thankful for any answers

BR,
Mikael

Galen Collins

unread,
Dec 15, 2014, 4:10:07 PM12/15/14
to pymo...@googlegroups.com
Mikael,

Can you send me the code you have so far as well as a strong use case you are trying to achieve?  For example, if you would like to have a modbus server where writes go to a database, you can actually plug in a database implementation for the data-store (this code can be used as starting point): https://pymodbus.readthedocs.org/en/latest/examples/database-datastore.html

The general idea is that you can plug in a different datastore to do _something_ with the data written via the modbus protocol. 

Galen

--
You received this message because you are subscribed to the Google Groups "pymodbus" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pymodbus+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Mikael Ljunggren

unread,
Dec 16, 2014, 8:43:00 AM12/16/14
to pymo...@googlegroups.com
Hi Galen,

Thank's for a quick reply

My use case is to setup a ModBusAsync server in my RaspberryPi to receive data from my PLC over GPRS, on demand and by pushing data on certain events such as alarms
I wan't to evaluate the data in a python module before pushing it to the database, that way I will get much more structured data
I also use MySQL database for my other apps like weather station etc

I have just used the Updating Server Example to try and see if I could get the PLC data to be seen in the Debug data values (log.debug("new values: " + str(values)))

But I can't even get that working…

My PLC sends data from inputs and outputs (type code 0x1, 0x2)

Code below

I must admit that I'm still learning python but sees this as a good project to learn, so bare with my newbie questions :-)

Regards,
Mikael

#!/usr/bin/python


import sys
sys
.path.append(r'/home/pi/pysrc')
import pydevd
pydevd
.settrace('host') # replace IP with address
                               
# of Eclipse host machine
                               
'''
Pymodbus Server With Updating Thread
--------------------------------------------------------------------------


This is an example of having a background thread updating the
context while the server is operating. This can also be done with
a python thread::


    from threading import Thread


    thread = Thread(target=updating_writer, args=(context,))
    thread.start()
'''

#---------------------------------------------------------------------------#
# import the modbus libraries we need
#---------------------------------------------------------------------------#
from pymodbus.server.async import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer


#---------------------------------------------------------------------------#
# import the twisted libraries we need
#---------------------------------------------------------------------------#
from twisted.internet.task import LoopingCall


#---------------------------------------------------------------------------#
# configure the service logging
#---------------------------------------------------------------------------#
import logging
logging
.basicConfig()
log
= logging.getLogger()
log
.setLevel(logging.DEBUG)


#---------------------------------------------------------------------------#
# define your callback process
#---------------------------------------------------------------------------#
def updating_writer(a):
   
''' A worker process that runs every so often and
    updates live values of the context. It should be noted
    that there is a race condition for the update.


    :param arguments: The input arguments to the call
    '''

    log
.debug("updating the context")
    context  
= a[0]
   
register = 1
    slave_id
= 0x01
    address  
= 0x00
    values  
= context[slave_id].getValues(register, address, count=1)
#   values   = [v + 1 for v in values]
    log
.debug("new values: " + str(values))
#   context[slave_id].setValues(register, address, values)


#---------------------------------------------------------------------------#
# initialize your data store
#---------------------------------------------------------------------------#
store
= ModbusSlaveContext(
    di
= ModbusSequentialDataBlock(0, [0]*0xff),
    co
= ModbusSequentialDataBlock(0, [0]*0xff),
    hr
= ModbusSequentialDataBlock(0, [0]*0xff),
    ir
= ModbusSequentialDataBlock(0, [0]*0xff))
context
= ModbusServerContext(slaves=store, single=True)


#---------------------------------------------------------------------------#
# initialize the server information
#---------------------------------------------------------------------------#
identity
= ModbusDeviceIdentification()
identity
.VendorName  = 'pymodbus'
identity
.ProductCode = 'PM'
identity
.VendorUrl   = 'http://github.com/bashwork/pymodbus/'
identity
.ProductName = 'pymodbus Server'
identity
.ModelName   = 'pymodbus Server'
identity
.MajorMinorRevision = '1.0'


#---------------------------------------------------------------------------#
# run the server you want
#---------------------------------------------------------------------------#
time
= 5 # 5 seconds delay
loop
= LoopingCall(f=updating_writer, a=(context,))
loop
.start(time, now=False) # initially delay by time

Mikael Ljunggren

unread,
Dec 18, 2014, 9:37:09 AM12/18/14
to pymo...@googlegroups.com
Hi again,

Sorry, but I am still not sure about how to solve my problem

Should I use callback server instead?
In that case how is the device map file to be set up?

I have an Easy Logic PLC where the first 8 inputs go from 0 to 7 in adress range and the outputs also goes from 0 to 7 but then with a different type code (01 = inputs, 02 = outputs)
I have set it to upload ModBus data on request by SMS, when requested the asyncronus server receives data correctly and debug write in the terminal shows that data is received but I can't figure out how to get hold of that data so that I can verify and manipulate that data before populating a dashboard page with in- and output status

I guess it will end up in the data store but here is where I get lost

Regards,
Mikael

Galen Collins

unread,
Dec 21, 2014, 10:20:48 PM12/21/14
to pymo...@googlegroups.com

Okay,

So you can use the decorator pattern around either the slave context or the datastore. Basically something like this:

class MyContext(object):

    def __init__(self, context):
        self.context = context # the real slave context

    def setValuea(self, f, a, v):
        # do your before work here
        self.context.setValues(f,a,v)
        # do your after work here

slave = MyContext(real_slave)

Does this make sense? Sorry I am on my phone or I would write it for you (if you need a better explanation I will send it to you when I get back to a computer).

Galen

Mikael Ljunggren

unread,
Dec 22, 2014, 5:26:25 AM12/22/14
to pymo...@googlegroups.com
Thank's Galen!

It could be that I don't really understand the concept around context and datastore but please add more code if you have the time to

I also wonder if the case I have with my PLC (acting as client/master) that sends data to my modbus server/slave with the function code 139 (GPRS upload  fixed function code on Easy PLC) could mess things up?

If I have understood things right, the inputs 0 - 7 are on memory adress 0 to 7 with (1x) with no offset and that means 1000 to 1007 decimal or?
Outputs are on 0 - 7 with (0x) and that means 0000 to 0007 or?

In my example how would the initialization of the datastore look like?

Regards,
Mikael

Galen Collins

unread,
Jan 5, 2015, 2:14:53 AM1/5/15
to pymo...@googlegroups.com
Mikael,

Sorry for the delay, I have been a little busy. Anyways, here is the code example that you should be able to modify to suit your needs. The difference between a context and a datablock (in terms of pymodbus) is that a server can have N contexts (one for each emulated slave) each of which can have its own datablock (one for discretes, coils, input registers, and holdring registers or a unique one for each). Does that make sense?

As for the addressing, your second statement is correct: Outputs are on 0 - 7 with (0x) and that means 0000 to 0007 or?

Galen
publishing-server.py
Reply all
Reply to author
Forward
0 new messages