Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
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')
--> 296 self._genericCommand(functioncode, registeraddress, value, numberOfDecimals, signed=signed)
/usr/local/lib/python3.5/dist-packages/minimalmodbus.py in _genericCommand(self, functioncode, registeraddress, value, numberOfDecimals, numberOfRegisters, signed, payloadformat)
696 ## Communicate ##
--> 697 payloadFromSlave = self._performCommand(functioncode, payloadToSlave)
699 ## Check the contents in the response payload ##
/usr/local/lib/python3.5/dist-packages/minimalmodbus.py in _performCommand(self, functioncode, payloadToSlave)
797 # Extract payload
--> 798 payloadFromSlave = _extractPayload(response, self.address, self.mode, functioncode)
799 return payloadFromSlave
/usr/local/lib/python3.5/dist-packages/minimalmodbus.py in _extractPayload(response, slaveaddress, mode, functioncode)
1087 if receivedFunctioncode == _setBitOn(functioncode, BITNUMBER_FUNCTIONCODE_ERRORINDICATION):
-> 1088 raise ValueError('The slave is indicating an error. The response is: {!r}'.format(response))
1090 elif receivedFunctioncode != functioncode:
ValueError: The slave is indicating an error. The response is: '\x02\x90\x01}À'`
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:
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:
Function code 6: Write single register
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.
–
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.