Cpp DLMS client launch example

58 posts / 0 new
Last post
Ingvar
Cpp DLMS client launch example

Good day!
In the GuruxDLMSClientExample example, the application is launched with the parameters - IP, port, as well as the parameter 'o' - OutputFile (as I understand the file with DLMS meters objects)
Is there an example of the application launch line and this file (any) for Windows? This would make learning code easier.
thanks

Kurumi
Kurumi's picture

Hi,

The command-line parameters depend from the meter. -o is optional and it's used to make meter reading faster. I understand that reading DLMS meters can be a real pain. You should also check GXDLMSDirector. I believe it can help you to read your meter.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

Thanks for the answer.
Did I understand correctly - if an OutputFile is used, then variables from it are read, otherwise all meter variables are read?
I don’t have a meter yet, but I plan to get it soon. Therefore the question was more theoretical - I wanted to study the code in more detail.
Maybe you have an example of such a file and an example of a launch line (from any meter )?
Or maybe GXDLMSDirector can generate this file (I have not studied this product yet).

Kurumi
Kurumi's picture

Hi,

There is an association view that describes what kind of functionality meter can offer (registers, etc). Reading the association view is taking a long time and for this reason, the output file parameter is added. You can save it to the file and read it from there.

You can start GuruxDLMSServerExample. It's a simple meter and work against that.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

Thanks, the connection with the GuruxDLMSServerExample was established, the file was generated. Now trying to read individual OBIS. Please tell me in what format to specify readObjects variable?
I understand this is a comma-separated OBIS, but in this code uses colon too.
If I indicate this:
readObjects = "1.1.0.0.0.255: 0";
Does not read.
If so:
readObjects = "1.1.0.0.0.255";
Fails with error (p2 == NULL)
How to specify the OBIS I need?

Kurumi
Kurumi's picture

Hi,

Give command line parameter ex. -g 1.1.0.0.0.255:2

#2 is attribute index number that you want to read.

BR,

Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

Thanks for the answer.
Trying to read Profile Generic from GuruxDLMSServerExample - OBIS 1.0.99.1.0.255. I try to read ByRange - the server responds with a short message. Does it support reading in this mode?
I try to read ByEntry. The SetValue method returns 258 (DLMS_ERROR_CODE_INVALID_PARAMETER). How to read rows from a profile?

Kurumi
Kurumi's picture

Hi,

Have you read the capture objects list (Attribute index 2) before reading the buffer?
You must read it first.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

Thanks.
Only an attribute list attribute index is 3.
Another question. I correctly understood that in DLMS each OBIS and its indexes are read by individual requests? There is no possibility of polling several OBIS?

Kurumi
Kurumi's picture

Hi,

You can read multiple objects using ReadList-method.
Not all meters support it.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

Thanks for the answer. Two more questions:
1. If the exchange is carried out via HDLC, it is necessary to indicate the physical address of the counter (on the bus). How to do it correctly?
2. The Profile Generic object has attribute 4 — the capture period. By standard, it returns a value in seconds (or 0 if not automatic capture). When polling GuruxServer an object 1.0.99.1.0.255 of index 4, value 60 is returned. Do you convert the value to minutes? What will be returned if there is a monthly capture interval?

Kurumi
Kurumi's picture

Hi,

1. If you have only one counter in the bus you USUALLY can use address 1 for it. There are some older meters that can't handle this.
2. This value is not converted. This is set to zero for monthly interval and "End of billing period" -Script table object calls capture-method of profile generic.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

1. If I understand correctly, there is a Wrapper mode - on TCP, there is an HDLC - COM (Rs-485 etc). If there are several counters on the RS-485 bus, then how to correctly set the address in the client?
2. "This value is not converted" - then 60 is what? Minutes?
About the monthly archive - I understood

Ingvar

So how to work with several counters (set addresses) on the RS-485 when working through HDLC?

Kurumi
Kurumi's picture

Hi,

Each meter has own server address. You can try to count it from the serial number but all the meters are not supporting it. Try to read your meter with GXDLMSDirector. Change "Address Type" from Default to SerialNumber.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

How to get the value of CGXDLMSVariant from the classes GXDLMSData, GXDLMSRegister and others without using a row vector (GetValues)?
These classes have a GetValue function, but the GXDLMSObject base class does not. How then is it better to do it?
I wrote a virtual function in GXDLMSObject, which returns an empty CGXDLMSVariant from it. Everything works, but I would not want to change your code.

Kurumi
Kurumi's picture

Hi,

GXDLMSData::GetValue or GXDLMSRegister::GetValue methods returns value attribute (index #2).

If you have GXDLMSObject* you can check the object type and then get the data.
Something like this:

CGXDLMSObject* it =...

if (it->GetObjectType() == DLMS_OBJECT_TYPE_DATA)
{
CGXDataObject* d = (CGXDataObject*)it;
d->GetValue();
}

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

Of course, I know and tried this method.
It works however, but it is not considered an example of "good" programming.
Why not make the base class a virtual function? For heirs whose function is not overridden, an empty value (or exception) will be returned.

Kurumi
Kurumi's picture

Hi,

GetValue will work for Register and Data objects, but there are tens of objects that are not using value, and more importantly they are using complex data structures.

GetValue does not work because the data structure of each object is so different. There is no way to return collection of COSEM objects that is required for example with Push Setup.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

You're right. Redid it.
Another question. There is a group survey in DLMS. I tried using ReadList. It works fine with GuruxServer, but not with my device. Doesn't even try to send requests to the device. What is the reason for this?
Gurux Director have a group survey? I did not find such a setting.

Kurumi
Kurumi's picture

Hi,

Your meter don't support Multiple references. For this reason, each object must read separately.

https://www.gurux.fi/Gurux.DLMS.Conformance

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

Do I understand correctly that the Gurux server simulator supports encryption through port 4060?
What parameters should be specified when (password, authentication type, security)? I drove the parameters that are issued in the console window - an error is issued.
Through DLMS Director also failed to connect.

Kurumi
Kurumi's picture

Hi Ingvar,

Encryption is supported.
If you are using Short Name referencing use port 4060, but I believe that you want to use Logical Name referencing (it's the default) and you should use port 4061.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

DLMS Director connected. I'm trying to connect with my encryption from my code. The keys is set just like an array
Hammered like this:
char* password = NULL;
authentication = DLMS_AUTHENTICATION_HIGH_SHA256;
security = DLMS_SECURITY_AUTHENTICATION;
char dedicatedKey[16]={0x31,0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31};
char systemTitle[8]={ 0x41,0x42,0x43 ,0x44 ,0x45 ,0x46 ,0x47 ,0x48 };
char authenticationKey[16]={0xD0,0xD1 ,0xD2 ,0xD3 ,0xD4 ,0xD5 ,0xD6 ,0xD7 ,0xD8 ,0xD9 ,0xDA ,0xDB ,0xDC ,0xDD ,0xDE ,0xDF};
char blockCipherKey[16]={ 0x00,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07 ,0x08 ,0x09 ,0x0A ,0x0B ,0x0C ,0x0D ,0x0E ,0x0F };
int ServerAddress = CGXDLMSClient::GetServerAddress(ServerAddressIn,Address,4);
CGXDLMSSecureClient* cl = new CGXDLMSSecureClient(useLogicalNameReferencing, clientAddress, ServerAddress, authentication, password, interfaceType);

cl->GetCiphering()->SetSecurity(security);
cl->SetAutoIncreaseInvokeID(autoIncreaseInvokeID);
CGXByteBuffer bb;
if (systemTitle != NULL)
{
bb.Clear();
bb.SetHexString(systemTitle);
cl->GetCiphering()->SetSystemTitle(bb);
}
if (authenticationKey != NULL)
{
bb.Clear();
bb.SetHexString(authenticationKey);
cl->GetCiphering()->SetAuthenticationKey(bb);
}
if (blockCipherKey != NULL)
{
bb.Clear();
bb.SetHexString(blockCipherKey);
cl->GetCiphering()->SetBlockCipherKey(bb);
}
if (dedicatedKey != NULL)
{
bb.Clear();
bb.SetHexString(dedicatedKey);
cl->GetCiphering()->SetDedicatedKey(bb);
}
Connect does not occur:
[2020-06-02 17:40:15.530] TRACE : (127.0.0.1:4061) Tx: [0012] 7E A0 0A 00 02 00 03 03 93 A0 62 7E
[2020-06-02 17:40:16.036] TRACE : (127.0.0.1:4061) Rx: [0035] 7E A0 21 03 00 02 00 03 73 48 5C 81 80 12 05 01 80 06 01 80 07 04 00 00 00 01 08 04 00 00 00 01 53 3B 7E
[2020-06-02 17:40:16.036] SCRIPT : <<DLMS.Meter>> : AARQRequest failed (258) Invalid parameter.
What can be wrong?
Do you need a password in this mode?

Kurumi
Kurumi's picture

Hi,

SHA256 needs the password. Only GMAC doesn't use the password.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

What password then need to be specified? It is not displayed in the server window.
I tried to specify DLMS_AUTHENTICATION_HIGH_GMAC- also does not establish a connection.
[2020-06-03 9:56:27.016] SCRIPT : <<DLMS.Meter>> : read start
[2020-06-03 9:56:27.032] TRACE : (127.0.0.1:4061) Tx: [0012] 7E A0 0A 00 02 00 03 03 93 A0 62 7E
[2020-06-03 9:56:27.536] TRACE : (127.0.0.1:4061) Rx: [0035] 7E A0 21 03 00 02 00 03 73 48 5C 81 80 12 05 01 80 06 01 80 07 04 00 00 00 01 08 04 00 00 00 01 53 3B 7E
[2020-06-03 9:56:27.536] SCRIPT : <<DLMS.Meter>> : AARQRequest failed (258) Invalid parameter.
Code:
char* password = NULL;
authentication = DLMS_AUTHENTICATION_HIGH_GMAC;
security = DLMS_SECURITY_AUTHENTICATION;
char dedicatedKey[16]={0x31,0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31};
char systemTitle[8]={ 0x41,0x42,0x43 ,0x44 ,0x45 ,0x46 ,0x47 ,0x48 };
char authenticationKey[16]={0xD0,0xD1 ,0xD2 ,0xD3 ,0xD4 ,0xD5 ,0xD6 ,0xD7 ,0xD8 ,0xD9 ,0xDA ,0xDB ,0xDC ,0xDD ,0xDE ,0xDF};
char blockCipherKey[16]={ 0x00,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07 ,0x08 ,0x09 ,0x0A ,0x0B ,0x0C ,0x0D ,0x0E ,0x0F };

Ingvar

Specified the same parameters in GuruxDLMSClientExample - also does not connect.
Log:
TX: 10:30:50 7E A0 07 03 03 93 8C 11 7E
RX: 10:30:50 7E A0 1E 03 03 73 40 CC 81 80 12 05 01 80 06 01 80 07 04 00 00 00 01 08 04 00 00 00 01 53 3B 7E
TX: 10:30:50 7E A0 07 03 03 53 80 D7 7E
RX: 10:30:50 7E A0 1E 03 03 73 40 CC 81 80 12 05 01 80 06 01 80 07 04 00 00 00 01 08 04 00 00 00 01 53 3B 7E

Kurumi
Kurumi's picture

Hi,
Do you try to connect to GuruxDLMSServerExample or what is your meter model and type?
You have not set a password because this error is given. AARQRequest failed (258) Invalid parameter.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

I am trying from GuruxDLMSClientExample to connect to GuruxDLMSServerExample with encryption. And I can’t do it. What parameters should be specified, for example, in DLMS_AUTHENTICATION_HIGH_GMAC mode

Kurumi
Kurumi's picture

Hi,

Try with this:
GuruxDLMSClientExample -h localhost -p 4061 -a HighGmac -t Verbose

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

About SHA I understood. Now I set GMAC but anyway i get a mistake.
Please give an example of the client launch line in DLMS_AUTHENTICATION_HIGH_GMAC mode and the systemTitle, blockCipherKey, dedicatedKey parameters with those parameters that the server has by default (parameters -T,-A,-D,-B). Particularly interested in blockCipherKey

Ingvar

The polling went when I removed the assignment of values to the dedicatedKey, systemTitle, etc. arrays.
Do they need to be set? I thought that you need to specify the value that the server displays in the window.

Kurumi
Kurumi's picture

Hi,

Those are default keys. You can also set them, but they must be the same for client and server.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

Ok.
But why when I ask them - the survey does not go? Did I indicate them incorrectly?

Kurumi
Kurumi's picture

Hi,

You haven't set the correct authentication level or some of the keys are not valid.
WIth DLMS_AUTHENTICATION_HIGH_SHA256 you didn't set a password.

BR,

Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

About SHA I understood. Now I set GMAC but anyway i get a mistake.
Please give me an example of the client launch line in DLMS_AUTHENTICATION_HIGH_GMAC mode and the systemTitle, blockCipherKey, dedicatedKey parameters with those parameters that the server has by default (parameters -T,-A,-D,-B). Particularly interested in blockCipherKey

Kurumi
Kurumi's picture

Hi,

You can command line parameters given below. Those are default keys used by the server. You need to update them to the server-side also if you change them.
-T 4775727578313233 -A D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF -B 000102030405060708090A0B0C0D0E0F -D 00112233445566778899AABBCCDDEEFF

BR,

Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

I try with another device - there is a problem.
In authentication mode Low - everything is correct. But when I set High, the parameter values are not read.
[2020-07-02 17:20:38.319] TRACE : (192.168.100.4:12160) Tx: [0010] 7E A0 08 02 31 61 93 F6 12 7E
[2020-07-02 17:20:39.474] TRACE : (192.168.100.4:12160) Rx: [0035] 7E A0 21 61 02 31 73 19 C2 81 80 14 05 02 00 80 06 02 00 80 07 04 00 00 00 01 08 04 00 00 00 01 CE 6A 7E
[2020-07-02 17:20:39.491] TRACE : (192.168.100.4:12160) Tx: [0079] 7E A0 4D 02 31 61 10 13 43 E6 E6 00 60 3E A1 09 06 07 60 85 74 05 08 01 01 8A 02 07 80 8B 07 60 85 74 05 08 02 02 AC 12 80 10 29 23 BE 84 E1 6C D6 AE 52 90 49 F1 F1 BB E9 EB BE 10 04 0E 01 00 00 00 06 5F 1F 04 00 00 1E 1D FF FF 6A 52 7E
[2020-07-02 17:20:40.739] TRACE : (192.168.100.4:12160) Rx: [0091] 7E A0 59 61 02 31 30 55 FD E6 E7 00 61 4A A1 09 06 07 60 85 74 05 08 01 01 A2 03 02 01 00 A3 05 A1 03 02 01 00 88 02 07 80 89 07 60 85 74 05 08 02 02 AA 12 80 10 31 32 33 34 35 36 37 38 39 30 41 42 43 44 45 46 BE 10 04 0E 08 00 06 5F 1F 04 00 00 18 1D 00 64 00 07 B7 69 7E
[2020-07-02 17:20:40.739] SCRIPT : <<DLMS.Meter>> : Read OBIS 0.0.1.0.0.255 Index 2
[2020-07-02 17:20:40.808] TRACE : (192.168.100.4:12160) Tx: [0028] 7E A0 1A 02 31 61 32 BD 04 E6 E6 00 C0 01 81 00 08 00 00 01 00 00 FF 02 00 65 D7 7E
[2020-07-02 17:20:41.911] TRACE : (192.168.100.4:12160) Rx: [0020] 7E A0 12 61 02 31 52 8F 3B E6 E7 00 C4 01 81 01 0D 7B 6D 7E
[2020-07-02 17:20:41.911] SCRIPT : <<DLMS.Meter>> : Error getting time
I tried it through the DLMSDirector - communication with him is normal. I found out that the request is not being executed in my client, but immediately proceeds to reading the parameters:
17:12:47 Authenticating.
7E A0 2C 02 31 61 32 F4 EB E6 E6 00 C3 01 C1 00 0F 00 00 28 00 00 FF 01 01 09 10 87 32 4A 5D 97 22 18 0E 37 8D EE 7B 05 AA 6D B1 D6 FD 7E
17:12:48
7E A0 25 61 02 31 52 82 DF E6 E7 00 C7 01 C1 00 01 00 09 10 30 4D E9 E3 D6 DD 43 57 59 EA FE 1D EC 2D A8 8B 42 4A 7E
In my client, this happens because the IsAuthenticationRequired method returns False. On the test client - the same thing.
What could be the problem?
Put logs:
https://drive.google.com/file/d/1kTOKY7WItMgCxkWS7N4xRRQgsnpxQIKO/view?u...

Kurumi
Kurumi's picture

Hi,

Your meter returns wrong value and indicates that GetApplicationAssociationRequest is not needed.
This is meter issue, but you can fix this if you change this:
if (m_Parser->IsAuthenticationRequired())
to
if (m_Parser->GetAuthentication() > DLMS_AUTHENTICATION_LOW)

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

If the exchange is carried out over unstable networks (for example, GSM), then it is possible to lose parts of the response. In this case, you need to do a second poll of the same parameter, but for some reason it cannot be done.
I have made the following repeat option:
for (int error_count = 0; error_count < BreakFlagLimit; error_count++)
{
std::vector<CGXByteBuffer> data;
CGXReplyData reply;
int ret = 0;
if ((ret = m_Parser->Read(obj, AttributeIndex, data)) != DLMS_ERROR_CODE_OK ||
(ret = ReadDataBlock(data, reply)) != DLMS_ERROR_CODE_OK ||
(ret = m_Parser->UpdateValue(*obj, AttributeIndex, reply.GetValue()) != DLMS_ERROR_CODE_OK))
{
continue;
}
ret = GetValue(obj, AttributeIndex, Value);
return ret;
}
return DLMS_ERROR_CODE_FALSE;

However, when a second request is executed, the counter responds correctly, but the m_Parser-> GetData method returns DLMS_ERROR_CODE_FALSE until you open and close the session.
This code returns an error:
if (!target->IsComplete())
{
return DLMS_ERROR_CODE_FALSE;
}
The link is a piece of the log.
What is the correct way to re-poll the parameter in case of such errors?
https://drive.google.com/uc?export=download&id=1Df0neuXFuTAwnz3pPAj1CKh1...

Kurumi
Kurumi's picture

Hi,

I can't access your google you shared.

You should sent the generated packet again and wait for the reply. Are you using HDLC or WRAPPER framing?

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar
Kurumi
Kurumi's picture

Hi Ingvar,

We'll improve the client example for ANSI C++ to handle re-sending. It's released today.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

ANSI C? Not Cpp Client?
Is the release already uploaded?
I don't see new commits.
https://github.com/Gurux/GuruxDLMS.c

Kurumi
Kurumi's picture

Hi,

The original topic was Cpp DLMS client launch example. Please, if you have a new question create a new topic.

I'll check if we can improve the ANSI C example as well.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

I just need it CppClient - ANSI C not needed
Editing commiting on GitHub?

Ingvar

I tried a new version of the client, unfortunately it doesn't work.
I put in 9 tries.
Immediately after the start, I disconnect the wire from the meter, and immediately set it back. The connection is not restored.
Here is the link to the log:
https://drive.google.com/uc?export=download&id=1QX1BGiIJPtdwZBOsXrHx10BW...
As I understand it, every DLMS request must have a new request ID. And in your implementation, the request is always the same with every new attempt:
Read failed.
7E A0 37 03 03 B0 E7 4E 16 01 00 01 00 02 04 12 00 01 11 00 09 06 01 FFData send failed. Try to resend 1/3
Read failed.
7E A0 37 03 03 B0 E7 4E 16 01 00 01 00 02 04 12 00 01 11 00 09 06 01 FFData send failed. Try to resend 2/3
Read failed.
7E A0 37 03 03 B0 E7 4E 16 01 00 01 00 02 04 12 00 01 11 00 09 06 01 FFData send failed. Try to resend 3/3
Therefore, if the device received a request, but the response was lost, then it will not work.

Kurumi
Kurumi's picture

Hi,

Client example can handle if message is lost, What you do is you break the connection. The only way to handle it is you established the connection again.

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

I didn't really understand your answer. If the client loses connection, will it be possible to establish it only if the connection is closed and opened?
Look at my last log (dated August 7) - there I make new polling attempts, and the counter replies something, but the client himself discards such an answer. Why?

Kurumi
Kurumi's picture

Hi,

The current example tries to resend data if the reply is not received from the meter.
In this case, the connection is still up. What you do when you remove the cable is that you broke the connection. There is no way to find out what is the reason for this and how long the application must wait before trying to establish a new connection.

The application can handle if the GSM network is not working well. It'll try to resend the data,
but it can't handle if GSM network is down.

BR,
Mikko

BR,
Mikko

________________________________________
Mikko Kurunsaari
Gurux Ltd
http://www.gurux.fi

Ingvar

"The application can handle if the GSM network is not working well."
In the log from August 7th, a situation arose in which the request went away, and the response was lost or corrupted. If you send a request similar to the previous one (as in the current implementation of the example), then the device does not respond.
Now I'm wondering why, if I send a new request as I do in the example of August 7, the counter responds (and it seems even correct), and the client himself discards such an answer. Or is the counter response incorrect?

Pages