I am trying to upgrade meter firmware but am stuck with the block size issue.
Here is the simple code, which was in another topic:
tr = GXDLMSImageTransfer
imageBlockValue = # Read this from the file.
frames = tr.imageBlockTransfer(client, imageBlockValue, None)
So, the question is how to read imageBlockValue from the file. I check description details in Blue Book but it is still not clear how to do it in Python library.
It could be nice to have a Python example for the firmware upgrade.
There is no single answer for this. Some meter manufacturers are saving firmware as binary data for the file. Some are using Hex string and some are using XML.
So you need to check how data is saved for the file and then read it for the imageBlockValue.
I'll add a firmware update for the work list, but it will take some time before it's ready.
In the meantime you can check how it's done in C# from here:
I understand that the format can be completely different, depending on the meter vendor. It is a relatively simple task to cope with formats. But my question is: do we need to get imageBlockValue from the image file or we can defined any size with the requirement that it should be less then PDU maximum allowed size?
Here is the table from DLMS Blue Book related to FW image::
All this is handled automatically by the framework. ImageBlockTransfer method splits the firmware image to correct frames.
Just call those methods in that order and you can transfer the image for the meter.
Then you need to call verify and activate. You need usually to wait for a while before calling activate. Verification must be finished and it might take a long time with some meters.
I followed code samples for C#, as you suggested. and adapted it for Python but it seems doesn't work properly.
The problem is with "imageTransferInitiate()" function. Here is a code:
CODE:
# 'reader' is properly initiated for network connections already
Access Error : Device reports a unmatched type.
Traceback (most recent call last):
File "DLMS/GXClient.py", line 841, in upgradeFirmware
init_val = reader.readDataBlock(init_data, reply)
File "DLMS/GXDLMSReader.py", line 190, in readDataBlock
self.readDataBlock(it, reply)
File "DLMS/GXDLMSReader.py", line 194, in readDataBlock
self.readDLMSPacket(data, reply)
File "DLMS/GXDLMSReader.py", line 128, in readDLMSPacket
self.readDLMSPacket2(data, reply)
File "DLMS/GXDLMSReader.py", line 183, in readDLMSPacket2
raise GXDLMSException(reply.error)
gurux_dlms.GXDLMSException.GXDLMSException: Access Error : Device reports a unmatched type.
So, what I understood, the meter doesn't accept the message because it is expecting the different type.
The "readDataBlock" command works absolutly fine for other type of commands, like disconnect/reconnect: reader.readDataBlock(obj.remoteReconnect(reader.client), reply)
or
reader.readDataBlock(obj.remoteDisconnect(reader.client), reply)
Also I read data from the meter for 0.0.44.0.0.255:
CODE:
for i in (2,3,4,5,6,7):
val = reader.read(ImageTransfer, i)
log_message = "----> Reading: Type: {}, Name: {}, LN: {}:{}, Value: {} ".format(str(ImageTransfer.objectType), ImageTransfer.description, str(ImageTransfer.name), i, val)
self.logger.info(log_message)
Hi Ilya,
Hi Ilya,
There is no single answer for this. Some meter manufacturers are saving firmware as binary data for the file. Some are using Hex string and some are using XML.
So you need to check how data is saved for the file and then read it for the imageBlockValue.
I'll add a firmware update for the work list, but it will take some time before it's ready.
In the meantime you can check how it's done in C# from here:
https://github.com/Gurux/Gurux.DLMS.Net/blob/1643b7228552ad2c37f1320928…
BR,
Mikko
Hi Mikko,
Hi Mikko,
I understand that the format can be completely different, depending on the meter vendor. It is a relatively simple task to cope with formats. But my question is: do we need to get imageBlockValue from the image file or we can defined any size with the requirement that it should be less then PDU maximum allowed size?
Here is the table from DLMS Blue Book related to FW image::
ImageBlock 0 -> Image Block Size
ImageBlock 1 -> Image Block Size
ImageBlock 2 -> Image Block Size
ImageBlock 3 -> Image Block Size
...
ImageBlock n-1 -> Image Block Size
ImageSize = SUM(<Image Block Sizes>)
Can I use any block size (below maximum of course) or it is predefined in the FW image (when the image was build) and must be used for the transfer?
Thank you,
Ilya
Hi Ilya,
Hi Ilya,
The maximum size must be smaller than the image block size (Attribute index #2), not PDU size. For that reason attribute index is read first.
http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSImageTransfer
All this is handled automatically by the framework. ImageBlockTransfer method splits the firmware image to correct frames.
Just call those methods in that order and you can transfer the image for the meter.
Then you need to call verify and activate. You need usually to wait for a while before calling activate. Verification must be finished and it might take a long time with some meters.
BR,
Mikko
Hi Mikko,
Hi Mikko,
I followed code samples for C#, as you suggested. and adapted it for Python but it seems doesn't work properly.
The problem is with "imageTransferInitiate()" function. Here is a code:
CODE:
# 'reader' is properly initiated for network connections already
ImageTransfer = GXDLMSImageTransfer()
reply = GXReplyData()
# Step 1: read Image Block Size from the meter
imageBlockSize = reader.read(ImageTransfer, 2)
print({"imageBlockSize":imageBlockSize, "type":type(imageBlockSize)})
# Step 2: Initiate the Image transfer process.
fw_filename = "fw/V1.01.bin"
imageIdentifier = "V1.01";
forImageSize = int(os.path.getsize(fw_filename))
print({"forImageSize":forImageSize})
init_data = ImageTransfer.imageTransferInitiate(reader.client, imageIdentifier, forImageSize)
print({"init_data":init_data})
init_val = reader.readDataBlock(init_data, reply)
print({"init_val":init_val})
RESULT:
{'imageBlockSize': 256, 'type': <class 'gurux_dlms.GXUInt32.GXUInt32'>}
{'forImageSize': 66105}
{'init_data': [bytearray(b'\x00\x01\x00P\x00\x01\x00/\xcb-0\x00\x00\x00\x03\x16\xee\xd9@&8gPY\xda\xdd\xdcSH\xea\xb9\xca\xb1L\xb1\xce*\x97\xa0I-\xa1\xc0\x01\xc0\xb9}\xc4b\xcf\xc3\x9c\x98\xceF')]}
Access Error : Device reports a unmatched type.
Traceback (most recent call last):
File "DLMS/GXClient.py", line 841, in upgradeFirmware
init_val = reader.readDataBlock(init_data, reply)
File "DLMS/GXDLMSReader.py", line 190, in readDataBlock
self.readDataBlock(it, reply)
File "DLMS/GXDLMSReader.py", line 194, in readDataBlock
self.readDLMSPacket(data, reply)
File "DLMS/GXDLMSReader.py", line 128, in readDLMSPacket
self.readDLMSPacket2(data, reply)
File "DLMS/GXDLMSReader.py", line 183, in readDLMSPacket2
raise GXDLMSException(reply.error)
gurux_dlms.GXDLMSException.GXDLMSException: Access Error : Device reports a unmatched type.
So, what I understood, the meter doesn't accept the message because it is expecting the different type.
The "readDataBlock" command works absolutly fine for other type of commands, like disconnect/reconnect: reader.readDataBlock(obj.remoteReconnect(reader.client), reply)
or
reader.readDataBlock(obj.remoteDisconnect(reader.client), reply)
Also I read data from the meter for 0.0.44.0.0.255:
CODE:
for i in (2,3,4,5,6,7):
val = reader.read(ImageTransfer, i)
log_message = "----> Reading: Type: {}, Name: {}, LN: {}:{}, Value: {} ".format(str(ImageTransfer.objectType), ImageTransfer.description, str(ImageTransfer.name), i, val)
self.logger.info(log_message)
RESULT:
----> Reading: Type: ObjectType.IMAGE_TRANSFER, Name: , LN: 0.0.44.0.0.255:2, Value: 256
----> Reading: Type: ObjectType.IMAGE_TRANSFER, Name: , LN: 0.0.44.0.0.255:3, Value:
----> Reading: Type: ObjectType.IMAGE_TRANSFER, Name: , LN: 0.0.44.0.0.255:4, Value: 0
----> Reading: Type: ObjectType.IMAGE_TRANSFER, Name: , LN: 0.0.44.0.0.255:5, Value: True
----> Reading: Type: ObjectType.IMAGE_TRANSFER, Name: , LN: 0.0.44.0.0.255:6, Value: 0
----> Reading: Type: ObjectType.IMAGE_TRANSFER, Name: , LN: 0.0.44.0.0.255:7, Value: [<gurux_dlms.objects.GXDLMSImageActivateInfo.GXDLMSImageActivateInfo object at 0x7ffc006d0fa0>]
So, can you please point to the right direction what is wrong with it and why I can't initiate the transfer?
Thanks a lot,
Ilya