Hi,
I have a problem reading scalars and units from a DLMS/COSEM counter correctly using the Gurux.DLMS library in Python. I am trying to read data from a Profile Generic object with OBIS code 1.0.99.1.0.255.
When I read the data, the values are returned in raw form (e.g. 2923 instead of 2.923). Even though I read the scales and units from the attribute of 3 registry objects (REGISTER or EXTENDED_REGISTER), the scales are always 1 and the units are empty.
I am attaching the code:
def read_and_save_measurements(reader, start_time, end_time, output_file="output.csv"):
try:
profile_object = next(
(obj for obj in reader.client.objects.getObjects(ObjectType.PROFILE_GENERIC)
if obj.logicalName == "1.0.99.1.0.255"),
None
)
if not profile_object:
print("Profil 1 nie został znaleziony.")
return
print(f"Znaleziono profil: {profile_object.name} ({profile_object.logicalName})")
with open(output_file, "w", newline="") as f:
writer = csv.writer(f, delimiter=';')
capture_objects = reader.read(profile_object, 3)
header_names = []
scalars = {}
units = {}
for i, obj in enumerate(capture_objects):
try:
logical_name = obj[0] if isinstance(obj, tuple) and len(obj) > 0 else obj.logicalName
header_names.append(logical_name)
if hasattr(obj, 'objectType') and obj.objectType in [ObjectType.REGISTER, ObjectType.EXTENDED_REGISTER]:
register = obj
register = reader.read(register, 3)
scaler = getattr(register, 'scaler', None)
if scaler is not None:
scalars[logical_name] = 10 ** scaler
else:
scalars[logical_name] = 1
unit_code = getattr(register, 'unit', None)
units[logical_name] = GXDLMSConverter.getUnitAsString(unit_code) if unit_code else ""
else:
scalars[logical_name] = 1
units[logical_name] = ""
except Exception as e:
print(f"Błąd podczas odczytu skali i jednostek dla obiektu {i}: {e}")
scalars[logical_name] = 1
units[logical_name] = ""
header_names_with_units = [f"{name} [{units.get(name, '')}]" for name in header_names]
writer.writerow(header_names_with_units)
try:
result = reader.readRowsByRange(profile_object, start_time, end_time)
if not result:
print(f"Brak danych dla profilu {profile_object.name} w podanym zakresie czasowym.")
return
except Exception as e:
print(f"Błąd podczas odczytu danych z zakresu {start_time} - {end_time}: {e}")
return
all_data = {}
for row_idx, row in enumerate(result):
if len(row) != len(header_names):
print(f"Niezgodna liczba kolumn w wierszu {row_idx}: {len(row)} (oczekiwano {len(header_names)})")
continue
timestamp = None
row_data = {}
for i, value in enumerate(row):
if i == 0 and isinstance(value, GXDateTime):
timestamp = datetime(
value.value.year,
value.value.month,
value.value.day,
value.value.hour,
value.value.minute,
value.value.second
).strftime("%Y-%m-%d %H:%M:%S")
elif i < len(header_names):
logical_name = header_names[i]
scalar = scalars.get(logical_name, 1)
scaled_value = value * scalar if isinstance(value, (int, float)) else value
print(f"Logiczna nazwa: {logical_name}, Surowa wartość: {value}, Skala: {scalar}, Skalowana wartość: {scaled_value}")
row_data[logical_name] = scaled_value
else:
print(f"Ostrzeżenie: brakujący nagłówek dla kolumny {i}.")
if timestamp:
all_data.setdefault(timestamp, {}).update(row_data)
for timestamp, values in sorted(all_data.items()):
row = [timestamp]
for header in header_names[1:]:
row.append(values.get(header, "-"))
writer.writerow(row)
print(f"Pomiary zapisano do pliku {output_file}")
except Exception as e:
print(f"Błąd podczas odczytu pomiarów: {e}")
Thanks in advance!
Hi, You need to loop all…
Hi,
You need to loop all capture objects before reading the buffer and if it's register or demand register, you need to read or set scaler. Something like this:
for k, v in pg.captureObjects:
if isinstance(k, GXDLMSRegister) v.attributeIndex == 2:
self.Read(k, 2)
#Read buffer...
BR,
Mikko