1

data blocks I cant seem to be able to read

I'm only quite new to python and modbus and I have been struggling to work out how to read the MSBytes and LSBytes of this controller using both pymodbus and minimalmodbus for a week or two now so hopefully someone in the brains trust here might be able to poke me in the right direction.

This particular controller has 3 digital/coil registers (2 register addresses are read only with 8 MSBytes and 8 LSBytes and one register 1536 as pictured above which has read and write 8 MSbytes and 8 LSBytes) However I'm confused because I can't seem to be able to work out how to read them correctly.

I only seem to get errors when I try to read them with a read_coil/bits only function but read_register and read_registers functions returns a single boolean result of 0 or 1 with a count of 1 register.

Using minimalmodbus

instrument.read_register(1536)

returns: 0

instrument.read_registers(1536, 1)

returns: [0]

instrument.read_bit(1536)

returns: error

UPDATE 12-09-2018:

Reading register when control is Off/standby.

In: client.read_register(1536, 0, 3, False) Out: 1

Reading register when control is On.

In: client.read_register(1536, 0, 3, False) Out: 0

Reading register when control is in defrost.

In: client.read_register(1536, 0, 3, False) Out: 4

Response from trying to write to registers:

The control documentation says to use functioncode 6 to write changes to registers however it seems to take the new value without error but doesn't update or change the controller register.

If I use functioncode 6

In: client.write_register(1536, 1, 0, 6, False) (no error or output, and register value doesn't change)

If I use functioncode 16 as suggested it leaves the following error.

In: client.write_register(1536, 1, 0, 16, False)


ValueError                                Traceback (most recent call last)
<ipython-input-22-66ccb391e76c> in <module>()
----> 1 client.write_register(1536, 1, 0, 16, False)

/usr/local/lib/python3.5/dist-packages/minimalmodbus.py in write_register(self, registeraddress, value, numberOfDecimals, functioncode, signed)
    294         _checkNumerical(value, description='input value')
    295
--> 296         self._genericCommand(functioncode, registeraddress, value, numberOfDecimals, signed=signed)
    297
    298

/usr/local/lib/python3.5/dist-packages/minimalmodbus.py in _genericCommand(self, functioncode, registeraddress, value, numberOfDecimals, numberOfRegisters, signed, payloadformat)
    695
    696         ## Communicate ##
--> 697         payloadFromSlave = self._performCommand(functioncode, payloadToSlave)
    698
    699         ## Check the contents in the response payload ##

/usr/local/lib/python3.5/dist-packages/minimalmodbus.py in _performCommand(self, functioncode, payloadToSlave)
    796
    797         # Extract payload
--> 798         payloadFromSlave = _extractPayload(response, self.address, self.mode, functioncode)
    799         return payloadFromSlave
    800

/usr/local/lib/python3.5/dist-packages/minimalmodbus.py in _extractPayload(response, slaveaddress, mode, functioncode)
   1086
   1087     if receivedFunctioncode == _setBitOn(functioncode, BITNUMBER_FUNCTIONCODE_ERRORINDICATION):
-> 1088         raise ValueError('The slave is indicating an error. The response is: {!r}'.format(response))
   1089
   1090     elif receivedFunctioncode != functioncode:

    ValueError: The slave is indicating an error. The response is: '\x02\x90\x01}À'`
Carlo Zanocco
  • 1,967
  • 4
  • 18
  • 31
Cory C
  • 125
  • 1
  • 9

1 Answers1

3

If you use read_bit function:

read_bit(registeraddress, functioncode=2)

read_bit(1536, 2)

EDIT: This function can read only the first bit of the address. If you have more than one bit on in the address you can't use this function or you will recive the error.

If you use the read_register function:

read_register(registeraddress, numberOfDecimals=0, functioncode=3, signed=False)

read_register(1536,0,3,False)

as output you will recive an Unsigned Int

If you use read_registers:

read_registers(registeraddress, numberOfRegisters, functioncode=3)

read_registers(1536, 1, 3)

As you can read here:

enter image description here

For asking modification to the device you have to write the MSByte and the LSByte.

SOLUTION:

import minimalmodbus

def _intToBin(toConvert):
    #Here you convert the int value to binary, after that to string getting from index 2 to 10
    MSByte = str(bin(toConvert))[2:10]
    #Here you convert the int value to binary, after that to string getting from index 10 to 18
    LSByte = str(bin(toConvert))[10:18]

    final = MSByte+LSByte

    return final

def _binToInt():
    return int(value,2)

def _changeBit(bitToChange, binVal, valueToSet):
    #Set the single bit
    tmpList = list(binVal)
    finalString = ""

    tmpList[bitToChange] = str(int(valueToSet))

    for x in tmpList:
        finalString += x

    return finalString


# DEFAULT CONFIG OF minimalmodbus
ReadType = minimalmodbus.MODE_RTU
minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = True
minimalmodbus.BAUDRATE = 19200
minimalmodbus.PARITY = 'E'
minimalmodbus.BYTESIZE = 8
minimalmodbus.STOPBITS = 1
minimalmodbus.TIMEOUT = 0.05

modbusAddress = 1536

instrument = minimalmodbus.Instrument("/dev/tty.usbserial-A9CVVTT5",1,mode="rtu")
instrument.debug = True

readValue = instrument.read_register(modbusAddress,0,3,False)
#This is to demostrate that the conversion works fine
print "This is the pure readed value: " + str(readValue)
binValue = _intToBin(readValue)
print "This is the value after the binary conversion, if you want to come back to int: " + str(int(binValue,2))

#Here you can change the state of your converted value
print "Before change binary value: " + binValue
changeBit = _changeBit(3,binValue,False)
print "Single bit change: " + str(changeBit)

print "Int after bit value change: " + str(_binToInt(changeBit))
#After that you can write back your register
instrument.write_register(modbusAddress,_binToInt(changeBit),0,16,False)

OUTPUT:

This is the pure readed value: 65472
This is the value after the binary conversion, if you want to come back to int: 65472
Before change binary value: 1111111111000000
Single bit change: 1110111111000000
Int after bit value change: 61376

UPDATE 12-09-2018:

Reading:

You are reading the register 1536, and it correctly returns the int value. So you only have to translate the int value to bin value, and to associate the translated bin value to the picture.

Writing:

As you can read in the documentation:

  1. Function code 6: Write single register
  2. Function code 16: Write multiple register

So this is the correct command:

client.write_register(1536, 1, 0, 6, False)

now, the problem is:

If you read under the picture the note is talking about writing LSByte and MSByte to make bit status changes.

So, you are writing the value 1 to the register 1536, but you are writing it only in the LSByte.

You have to write also in the MSByte, then:

LSByte = "00000001" # it is 1 in decimal
MSByte = "00000001" # it is 1 in decimal

ValueToSend = MSByte + LSByte
# The result value will be: "0000000100000001"
# If you convert it to decimal is: 257
#Then here you have to write
client.write_register(1536, 257, 0, 6, False)

The MSByte must be written to 1, to the LSByte corresponding bit.

For example:

  • Change standby status to 1: MSByte = "00000001" and the LSByte = "00000001"
  • Change standby status to 0: MSByte = "00000001" and the LSByte = "00000000"
  • Change cold room light to 1: MSByte = "00000010" and the LSByte = "00000010"
  • Change cold room light to 0: MSByte = "00000010" and the LSByte = "00000000"

You have to use the conversion from int to bin, change the bit value of the MSByte and LSByte, convert again from bin to int, and write the value.

Carlo Zanocco
  • 1,967
  • 4
  • 18
  • 31
  • Thanks for taking the time to write back. Reading the register and registers is no problem however it only extracts a boolean integer value of 0. If I try to read a bit as your example it gives an error: [The response is: '\x02\x82\x01q`]' which is whats giving me a headache! read_register(1536, 0, 3) - returns 0 but I don't know how to break that into string bits and read them. – Cory C Sep 11 '18 at 07:33
  • I have to make a test on my modbus device, i'll reply to you later! – Carlo Zanocco Sep 11 '18 at 07:58
  • thanks. If i do `read_string(1536, 1)` it returns: '\x00\x04' which converts to 0 & 4 in hex but that doesn't seem to line up with what the bits should be either... – Cory C Sep 11 '18 at 08:08
  • Check in my answer, I wrote a possible solution in there, I think it could help you! – Carlo Zanocco Sep 11 '18 at 14:22
  • Thanks Carlo, I think there must be something wrong with there documentation? I can run the first block of your code (converted to python3, and it still gives me a read value of 0) – Cory C Sep 12 '18 at 07:00
  • If I read the register and the controller is on I get a value of 0, if the controller is in standby I get a value of 1, if unit is in defrost is on I get a value of 4. If I try to write to the register using functioncode=16 I get an error (If I use functioncode=6 I don't get an error but the register value doesn't update - ducumentation says to use functioncode=6 to write register changes - it works for all the other single registers, just not this one). – Cory C Sep 12 '18 at 07:17
  • Can you edit your post and add the full code please? I'll take a look on this. The reading is working well then, the only problem is that you receive an error when you try to update the value in the register 1536, right? Post the full code and the output of the program, thanks – Carlo Zanocco Sep 12 '18 at 07:57
  • Have updated original post, hopefully with the information you're after. Cheers Cory – Cory C Sep 12 '18 at 09:04
  • I have updated my original post. I think we are near to the final solution! – Carlo Zanocco Sep 12 '18 at 09:23
  • You have solved my problem with this register my friend! I totally overlooked converting the bits to decimal, I should of caught on with your code earlier as well thank you Carlo ;) There is a few other read only registers similar to this one hopefully I can tackle next. Again thanks for your help and patients on this! – Cory C Sep 12 '18 at 09:40