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}À'`
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.
read_register(registeraddress, numberOfDecimals=0, functioncode=3, signed=False)
read_register(1536,0,3,False)
as output you will recive an Unsigned Int
read_registers(registeraddress, numberOfRegisters, functioncode=3)
read_registers(1536, 1, 3)
As you can read 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:
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:
MSByte = "00000001"
and the LSByte = "00000001"
MSByte = "00000001"
and the LSByte = "00000000"
MSByte = "00000010"
and the LSByte = "00000010"
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.