Skip to main content
Home
for DLMS smart meters
Open source solutions for DLMS smart metering

Main navigation

  • Home
  • Products
  • About us
  • Open Source
  • Community
  • Forum
  • Downloads
User account menu
  • Log in

Breadcrumb

  1. Home
  2. Problems Reading Scalars and Units From a Meter Using The Gurux.DLMS Library In Python

Problems reading scalars and units from a meter using the Gurux.DLMS library in Python

By kuba172 , 27 January, 2025
Forums
Gurux.DLMS

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!

Profile picture for user Kurumi

Kurumi

1 year 4 months ago

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

  • Create new account
  • Reset your password

Hire Us!

Latest Releases

  • Tue, 06/09/2026 - 11:16
    gurux.dlms.java 4.0.95
  • Tue, 06/09/2026 - 10:03
    Gurux.DLMS.Python 1.0.199
  • Mon, 06/08/2026 - 13:39
    gurux.dlms.cpp 9.0.2606.0801
  • Mon, 06/01/2026 - 10:15
    gurux.dlms.cpp 9.0.2606.0101
  • Thu, 05/28/2026 - 16:06
    gurux.dlms.java 4.0.94

New forum topics

  • Error reading L&G Meter
  • Pass a TCP Client to GXNet
  • Australian EDMI Mk10D (Essential Energy area)
  • Strange mix of data notificiation vs get response
  • DLMS Connection
More
RSS feed
Privacy FAQ GXDN Issues Contact
Follow Gurux on Twitter Follow Gurux on Linkedin