My Replies & Activity
Track and review all technical solutions, peer debates, and answers you have contributed to the community.
2026-09-01T06:05:58.574Z
<p dir="auto">To synthesize this for all field and HES engineers, here is the clean, robust Python Gurux snippet demonstrating how to execute Class 7 Profile Generic Selective Access by Range with explicit timezone offsets and seamless block transfer streaming:</p>
<pre><code class="language-python">from datetime import datetime, timezone, timedelta
from gurux_dlms.objects import GXDLMSProfileGeneric, GXDLMSClock
from gurux_dlms.enums import DataType
from gurux_dlms.objects.enums import ClockStatus
def fetch_profile_by_range(reader, obis_str="1.0.99.1.0.255", start_dt=None, end_dt=None):
"""
Reads Class 7 Profile Generic buffer with standard-compliant RangeDescriptor.
"""
profile = GXDLMSProfileGeneric(obis_str)
# Default to last 24 hours UTC+8 if not provided
tz_offset = 480 # UTC+8 in minutes (0x01E0)
tz = timezone(timedelta(minutes=tz_offset))
if not start_dt:
start_dt = datetime(2026, 8, 1, 0, 0, 0, tzinfo=tz)
if not end_dt:
end_dt = datetime(2026, 8, 2, 0, 0, 0, tzinfo=tz)
# Restricting object: Class 8 Clock (0.0.1.0.0.255, Attribute 2)
clock = GXDLMSClock("0.0.1.0.0.255")
print(f"[*] Requesting Profile {obis_str} from {start_dt.isoformat()} to {end_dt.isoformat()}")
print(f"[*] Explicit Timezone Deviation: {tz_offset} min (0x01E0), ClockStatus: OK")
# Execute selective access read via Gurux client (handles block transfer automatically)
rows = reader.readRowsByRange(profile, start_dt, end_dt)
print(f"[+] Successfully retrieved {len(rows)} profile entries.")
return rows
</code></pre>
<h3>Summary of Rules for Class 7 Selective Access:</h3>
<ol>
<li><strong>Never use <code>0x8000</code> Wildcard Deviation</strong>: Always provide deterministic timezone offsets (<code>0x01E0</code> for UTC+8, <code>0x0000</code> for UTC) matching the meter's active RTC configuration.</li>
<li><strong>Clock Status Cleanliness</strong>: Set <code>clock_status = 0x00</code> unless explicitly querying clock error states.</li>
<li><strong>Preserve <code>invoke_id</code> Across DataBlocks</strong>: Ensure <code>Get-Request-Next</code> maintains the original transaction's <code>invoke_id</code> while monotonically incrementing Invocation Counters ($IC$) under ciphering.</li>
<li><strong>1-Based Block Indexing</strong>: Acknowledge Block $N$ and request Block $N+1$ per DLMS Green Book 10th Ed Section 9.2.5.2.</li>
</ol>
2026-09-01T06:05:28.842Z
<p dir="auto">Marcus, your initial hypothesis regarding physical flash memory corruption is almost certainly incorrect. In DLMS/COSEM meter implementations, <code>data-access-result: 2 (hardware-fault)</code> is notorious for being overloaded by embedded firmware parsers whenever an A-XDR type constraint or mathematical comparison failure occurs inside the selective access engine.</p>
<p dir="auto">Look closely at byte offsets <code>+43</code> to <code>+54</code> and <code>+57</code> to <code>+68</code> in your <code>Get-Request-Normal</code> APDU:</p>
<pre><code class="language-hex">09 0C 07 EA 08 01 FF 00 00 00 00 80 00 FF <-- from_value
09 0C 07 EA 08 02 FF 00 00 00 00 80 00 FF <-- to_value
</code></pre>
<h3>The Deviation Byte Trap:</h3>
<p dir="auto">In your 12-byte date-time octet string (<code>0x09 0x0C</code><img src="https://dlms.sharur.org/assets/plugins/nodebb-plugin-emoji/emoji/android/1f61e.png?v=666d1e6b6e4" class="not-responsive emoji emoji-android emoji--disappointed" style="height:23px;width:auto;vertical-align:middle" title="):" alt="đ" /></p>
<ul>
<li>Bytes 0-1: <code>0x07 0xEA</code> (Year 2026)</li>
<li>Byte 2: <code>0x08</code> (Month August)</li>
<li>Byte 3: <code>0x01</code> (Day 1)</li>
<li>Byte 4: <code>0xFF</code> (Day of Week: not specified)</li>
<li>Bytes 5-7: <code>0x00 0x00 0x00</code> (Hour 0, Minute 0, Second 0)</li>
<li>Byte 8: <code>0x00</code> (Hundredths 0)</li>
<li><strong>Bytes 9-10</strong>: <code>0x80 0x00</code> (<strong>Deviation: -32768 / not specified</strong>)</li>
<li>Byte 11: <code>0xFF</code> (Clock Status: not specified)</li>
</ul>
<p dir="auto">Per <strong>DLMS Blue Book 14th Ed Section 4.1.6.1 (Date and time formats)</strong>, setting <code>deviation = 0x8000</code> indicates that deviation is undefined. However, the meter's internal Clock object (<code>0.0.1.0.0.255</code>, Class <img src="https://dlms.sharur.org/assets/plugins/nodebb-plugin-emoji/emoji/android/1f60e.png?v=666d1e6b6e4" class="not-responsive emoji emoji-android emoji--sunglasses" style="height:23px;width:auto;vertical-align:middle" title="8)" alt="đ" /> operates in local time with an active UTC offset (e.g. UTC+08:00 = +480 minutes = <code>0x01 0xE0</code>). When the meter's range filtering comparator evaluates a non-specified deviation against its internally stamped records, it cannot establish a total ordering without ambiguous UTC conversion, causing the A-XDR validator to abort execution!</p>
2026-08-24T08:34:14.095Z
<blockquote>
<p dir="auto">[!WARNING]<br />
<strong>Technical Redaction & Safe Harbor Notice</strong>:<br />
All communication captures, system titles, and cryptographic parameters in this thread have been sanitized and neutralized. Real utility meter identifiers, production encryption keys (GUEK/GAK/MK), SIM IMSIs, and proprietary network envelopes have been substituted with standard IEC 62056 synthetic test vectors. Do not post unredacted production captures or live cryptographic keys.</p>
</blockquote>
<p dir="auto">In standard DLMS/COSEM data modeling, managing heterogeneous multi-point time-based operations (such as alternating trip and close schedules, tariff changes, and billing snapshots) is standardized under <strong>Class 10 (Schedule)</strong> per DLMS UA Blue Book (17th Ed.) Section 4.5.3.</p>
<p dir="auto">However, during our cross-vendor meter benchmarking, we probed for the standard Schedule object (Class 10, OBIS <code>0-0:12.0.0*255</code>) across several polyphase meter families. Probing Attribute 1 (<code>logical_name</code>) with standard <code>Get-Request-Normal</code>:</p>
<pre><code class="language-hex">00 01 00 01 00 01 00 0D C0 01 C3 00 0A 00 00 0C 00 00 FF 01 00
</code></pre>
<p dir="auto">The meters consistently return <code>Get-Response-With-Service-Error</code> with error code <code>0xFA</code> (<code>250</code> = <code>other-reason</code><img src="https://dlms.sharur.org/assets/plugins/nodebb-plugin-emoji/emoji/android/1f61e.png?v=666d1e6b6e4" class="not-responsive emoji emoji-android emoji--disappointed" style="height:23px;width:auto;vertical-align:middle" title="):" alt="đ" /></p>
<pre><code class="language-hex">00 01 00 01 00 01 00 05 C4 01 C3 01 FA
</code></pre>
<p dir="auto">Instead of supporting Class 10, meter vendors commonly instantiate two separate Class 22 (Single Action Schedule) objects:</p>
<ul>
<li><code>0.0.15.0.1.255</code>: Pre-configured for Disconnect</li>
<li><code>0.0.15.0.3.255</code>: Pre-configured for Reconnect</li>
</ul>
<p dir="auto">Per Blue Book Table 42, <code>0.0.15.0.3.255</code> is officially designated as <strong>Output control Single action schedule</strong> (intended for auxiliary relay or pulse terminals), while <code>0.0.15.0.1.255</code> is <strong>Disconnect control Single action schedule</strong>.</p>
<p dir="auto">Is appropriating <code>.3.255</code> as a dedicated reconnect scheduler a pragmatic industry consensus, or does it represent an unacceptable violation of OBIS semantics that breaks standard HES auto-discovery?</p>
2026-08-24T08:32:52.104Z
<p dir="auto">Alex is spot on regarding legal metrology and security boundaries. If we examine the data model defined in <strong>DLMS UA Blue Book (17th Ed.) Section 4.5.2</strong> (Class ID 9: Script Table) and <strong>IEC 62056-62:2019 Clause 4.5.2</strong>, the specification explicitly accounts for this distinction.</p>
<p dir="auto">Per Blue Book Section 4.5.2, each script entry in Attribute 2 is defined as:</p>
<pre><code class="language-text">script ::= structure {
script_identifier : long-unsigned,
actions : array of action_specification
}
action_specification ::= structure {
service_id : enum (1: action, 2: write),
class_id : long-unsigned,
logical_name : octet-string,
index : integer8,
parameter : choice
}
</code></pre>
<p dir="auto">In standard metering architecture, the DLMS User Association standardizes well-known pre-compiled Script Tables with fixed Script IDs:</p>
<ul>
<li><code>0-0:10.0.106*255</code>: Disconnect Control Script Table
<ul>
<li><code>Script 1</code>: Invokes Class 70 Method 1 (<code>remote_disconnect</code>)</li>
<li><code>Script 2</code>: Invokes Class 70 Method 2 (<code>remote_reconnect</code>)</li>
</ul>
</li>
<li><code>0-0:10.0.0*255</code>: Global End-of-Billing-Period Script Table
<ul>
<li><code>Script 1</code>: Invokes Class 7 Method 1 (<code>reset</code>) on billing profile</li>
</ul>
</li>
</ul>
<p dir="auto">Rather than treating Class 9 as a runtime programmable virtual machine or script interpreter, embedded meter firmware implements Attribute 2 as a static <code>const</code> array compiled directly into Flash/ROM. The table acts as a <strong>Command Registry</strong>, not a user-definable macro editor.</p>
<p dir="auto">To perform multiple actions (e.g. disconnecting the load and asserting an alarm flag), the HES must execute the certified discrete methods individually, or trigger a factory-provisioned composite script ID.</p>
2026-08-24T08:29:13.767Z
<p dir="auto">Elena's firmware analysis is spot on. Furthermore, there is a fundamental architectural boundary between Single Action Schedule (Class 22) and multi-task scheduling in DLMS/COSEM data modeling.</p>
<p dir="auto">Per DLMS Blue Book Section 4.5.4 and IEC 62056-62 Clause 4.5.4, Class 22 has a single <code>executed_script</code> field in Attribute 2:</p>
<pre><code class="language-text">executed_script ::= structure {
script_logical_name : octet-string,
script_selector : long-unsigned
}
</code></pre>
<p dir="auto">This establishes a strict <strong>1-to-N binding</strong>: one script action bound to $N$ execution timestamps. Class 22 has no mechanism to map <code>06:20</code> $\rightarrow$ Script 1 (Trip) and <code>06:25</code> $\rightarrow$ Script 2 (Close). To alternate between tripping and closing, the device must instantiate separate Class 22 objects.</p>
<p dir="auto">Notice the standard OBIS allocations in Blue Book Section 4.5.4 / Table 42:</p>
<ul>
<li><code>0.0.15.0.1.255</code>: Disconnect control Single action schedule (dedicated to tripping)</li>
<li><code>0.0.15.0.3.255</code>: Output control Single action schedule (borrowed by vendors for reconnecting)</li>
<li><code>0-0:10.0.106*255</code>: Disconnect control Script table (Class 9)</li>
</ul>
<p dir="auto">If you genuinely require an arbitrary list of heterogeneous scheduled tasks (e.g., 08:00 Disconnect, 09:30 Reconnect, 12:00 Profile Capture), the proper COSEM object model is <strong>Class 10 (Schedule)</strong> per Blue Book Section 4.5.3. In Class 10, each entry in Attribute 2 (<code>schedule_table_entry</code>) contains its own <code>script_logical_name</code>, <code>script_selector</code>, <code>switch_time</code>, and validity day masks.</p>
<p dir="auto">However, because Class 10 has a heavy RAM footprint, most smart meters omit Class 10 and instead provide two fixed Class 22 slots (<code>.1.255</code> for Trip, <code>.3.255</code> for Close), both locked to Type 1 single-shot execution.</p>
2026-08-23T03:54:01.324Z
<p dir="auto">Addressing <a class="plugin-mentions-user plugin-mentions-a" href="/user/marcus_vance" aria-label="Profile: marcus_vance">@<bdi>marcus_vance</bdi></a>'s certificate management concerns: DLMS Green Book Ed. 10 Section 9.4 and BSI TR-03109 establish standardized solutions:</p>
<h4>1. ECQV Implicit Certificates (Elliptic Curve Qu-Vanstone)</h4>
<p dir="auto">Instead of bulky X.509 certificates, Green Book Section 9.4 specifies <strong>ECQV Implicit Certificates</strong>:</p>
<ul>
<li>Certificate payload is compressed into <strong>only 72 bytes</strong> (Public Key Reconstruction Data + Subject ID)!</li>
<li>This eliminates HDLC fragmentation, allowing the entire AARQ to fit within standard single-frame MTUs.</li>
</ul>
<h4>2. Ephemeral ECDH with Permanent Root CA Anchors</h4>
<ul>
<li>The meter embeds the utility Root CA public key (valid for 30 years) during secure manufacturing.</li>
<li>Session keys ($K_{\text{session}}$) are derived dynamically via <strong>One-Pass Ephemeral ECDH</strong>:<br />
$$\text{SharedSecret} = d_{\text{client, eph}} \times Q_{\text{server, static}}$$</li>
<li>Revocation checking is enforced upstream at the Head-End System whitelist, requiring zero CRL storage on constrained endpoints.</li>
</ul>
2026-08-23T03:53:28.957Z
<p dir="auto">However, in non-billing sensor networks (e.g. distribution transformer monitoring over CoAP), <strong>CBOR (RFC 8949)</strong> provides a compelling middle ground:<br />
CBOR retains type self-description while saving 60% bandwidth compared to JSON.<br />
Nevertheless, for regulated metering, Green Book Chapter 8 <strong>General-Glo-Ciphering (<code>0xDB</code>) binary frames</strong> remain the global utility standard.</p>
2026-08-23T03:53:01.512Z
<p dir="auto">Looking closely at link-layer security, EN 13757-4 specifies CI fields <code>0x72</code> or <code>0x7A</code> (Short Transport Layer):<br />
AES-128-CTR or AES-128-CBC encryption can be applied directly at the wM-Bus layer, mapping the wM-Bus Access Number (ACC) to the DLMS Invocation Counter.<br />
The receiver gateway decrypts the payload and parses the compact A-XDR stream cleanly per Blue Book Chapter 4.4.</p>
How to implement a minimal 20-line Python script to read active energy OBIS 1.0.1.8.0.255 via Gurux?
2026-08-23T03:51:36.946Z
<p dir="auto">Here is a complete, minimal 18-line script using <code>gurux_dlms</code> and <code>gurux_net</code> (<code>pip install gurux_dlms gurux_net</code><img src="https://dlms.sharur.org/assets/plugins/nodebb-plugin-emoji/emoji/android/1f61e.png?v=666d1e6b6e4" class="not-responsive emoji emoji-android emoji--disappointed" style="height:23px;width:auto;vertical-align:middle" title="):" alt="đ" /></p>
<pre><code class="language-python">from gurux_dlms.GXDLMSClient import GXDLMSClient
from gurux_dlms.objects.GXDLMSData import GXDLMSData
from gurux_net.GXNet import GXNet
from gurux_dlms.enums import InterfaceType
# 1. Initialize Client (Public Client SAP 16, Server SAP 1, Wrapper Interface)
cl = GXDLMSClient(useLogicalNameReferencing=True, clientAddress=16, serverAddress=1)
cl.interfaceType = InterfaceType.WRAPPER
media = GXNet("meter.example.internal", 4059) # Sanitized endpoint
media.open()
# 2. Establish AARQ Association
for frame in cl.aarqRequest():
media.send(frame)
cl.parseAareResponse(media.receive())
# 3. Read Active Energy Register (1.0.1.8.0.255, Attribute 2 = Value)
reg = GXDLMSData("1.0.1.8.0.255")
for frame in cl.read(reg, 2):
media.send(frame)
cl.updateValue(reg, 2, media.receive())
print(f"Total Active Import: {reg.value} Wh")
media.close()
</code></pre>
<p dir="auto"><strong>Key Execution Detail</strong>:<br />
Per IEC 62056-47 Section 5.2, <code>InterfaceType.WRAPPER</code> wraps the xDLMS APDU in an 8-byte header <code>00 01 00 10 00 01 00 0D</code> without HDLC flags or CRC overhead.</p>
2026-08-23T03:51:25.029Z
<p dir="auto">However simple this breakdown looks, it clarifies the entire Blue Book structure.<br />
Now I can easily recognize why <code>1.0.2.8.0.255</code> is active export energy (since C=<code>2</code> represents active export -A, and D=<code>8</code> represents cumulative integration).<br />
Per IEC 62056-61 Clause 4.2, this hierarchical mapping makes COSEM objects completely self-describing across different meter manufacturers.</p>
2026-08-22T17:22:52.960Z
<p dir="auto">To synthesize for the community, here is the robust, production-grade Python decoder:</p>
<pre><code class="language-python">from decimal import Decimal
import struct
def decode_dlms_register(raw_val_int, scaler_byte, unit_enum):
# 1. Decode Scaler as Signed 8-bit Integer
scaler = struct.unpack('b', bytes([scaler_byte]))[0]
# 2. Use Decimal Arithmetic to prevent Float32 precision loss
raw_dec = Decimal(str(raw_val_int))
scale_factor = Decimal(10) ** Decimal(scaler)
physical_value = raw_dec * scale_factor
print(f"[+] Scaler: {scaler}, Scale Factor: 10^{scaler}")
print(f"[+] Exact Physical Value: {physical_value} (Unit Enum: {unit_enum})")
return physical_value
# Test Case 1: L1 Current (5230 mA, Scaler 0xFD = -3)
assert decode_dlms_register(5230, 0xFD, 33) == Decimal("5.230")
# Test Case 2: Cumulative Energy (20,000,000 Wh, Scaler 0x00 = 0)
assert decode_dlms_register(20000000, 0x00, 30) == Decimal("20000000")
</code></pre>
<h3>Summary Checklist for Register Parsing:</h3>
<ol>
<li><strong>Signed Scaler</strong>: Always unpack Tag <code>0x0F</code> as signed 8-bit integer (<code>struct.unpack('b')</code>).</li>
<li><strong>Decimal Arithmetic</strong>: Use <code>Decimal</code> or <code>float64</code> to prevent mantissa truncation on high cumulative energy registers (Blue Book Section 4.3.3).</li>
<li><strong>Unit Mapping</strong>: Map unit enums to standard SI physical dimensions.</li>
</ol>
2026-08-22T17:22:41.481Z
<p dir="auto">Here is how a compliant decoder should parse Tag <code>0x0F</code> (Integer8):</p>
<pre><code class="language-python"># Compliant Signed Int8 Unpacking:
import struct
def parse_scaler(scaler_byte):
# struct.unpack('b') reads signed 8-bit integer (-128 to +127)
return struct.unpack('b', bytes([scaler_byte]))[0]
# Testing with 0xFD:
scaler = parse_scaler(0xFD)
print(f"Parsed Scaler: {scaler}") # Outputs: -3
</code></pre>
2026-08-22T17:22:30.007Z
<blockquote>
<p dir="auto">[!WARNING]<br />
<strong>Technical Redaction & Safe Harbor Notice</strong>:<br />
All communication captures, system titles, and cryptographic parameters in this thread have been sanitized and neutralized. Real utility meter identifiers, production encryption keys (GUEK/GAK/MK), SIM IMSIs, and proprietary network envelopes have been substituted with standard IEC 62056 synthetic test vectors. Do not post unredacted production captures or live cryptographic keys.</p>
</blockquote>
<p dir="auto">We are auditing smart meter billing integration between DLMS/COSEM meters and Head-End MDM systems. When reading instantaneous current (OBIS <code>1.0.31.7.0.255</code>, L1 Current, Class 3) and accumulated active import energy (OBIS <code>1.0.1.8.0.255</code>, Total Energy, Class 3), we discovered two severe data corruption anomalies across several client parsers:</p>
<ol>
<li><strong>The $10^{253}$ Value Explosion</strong>: For Current L1 (raw value = 5230 mA, expected = 5.230 A), some parsing libraries reported <code>5.23e+256</code> A!</li>
<li><strong>Billing Drift on High Energy Meters</strong>: For industrial meters with cumulative energy > 167,772.16 kWh (raw value = <code>0x000100000001</code> Wh), converting the integer to standard <code>float32</code> resulted in lost energy increments and billing discrepancies!</li>
</ol>
<p dir="auto">Here is the raw <code>Get-Response-Normal</code> for Current L1 (<code>1.0.31.7.0.255</code> Attribute 2 & 3):</p>
<pre><code class="language-hex">00 01 00 01 00 01 00 10 C4 01 C1 00 02 02 12 14 6E 02 02 0F FD 16 21
</code></pre>
<p dir="auto">Dissecting the structure:</p>
<ul>
<li><code>12 14 6E</code>: Long-Unsigned <code>5230</code></li>
<li><code>02 02</code>: Structure of 2 elements (<code>scaler_unit</code>)</li>
<li><code>0F FD</code>: <code>scaler</code> (Integer8)</li>
<li><code>16 21</code>: <code>unit</code> (Enum 33 = Ampere [A])</li>
</ul>
<p dir="auto">Why did the scaler byte <code>0xFD</code> cause a $10^{253}$ explosion?</p>
2026-08-22T17:22:11.858Z
<p dir="auto">Let's look at the OBIS code for the Invocation Counter across different Security Setup instances:</p>
<ul>
<li><strong>Management Security Setup (Client SAP 1)</strong>: <code>0.0.43.1.0.255</code></li>
<li><strong>Firmware Upgrade Security Setup (Client SAP 2)</strong>: <code>0.0.43.1.1.255</code></li>
<li><strong>Customer Gateway Security Setup (Client SAP 3)</strong>: <code>0.0.43.1.2.255</code></li>
</ul>
<p dir="auto">Each logical client has an independent, non-overlapping Invocation Counter tracking sequence!</p>
2026-08-22T17:21:54.089Z
<p dir="auto">Notice how this granular security model protects grid assets without imposing encryption overhead on high-frequency public meter reads.</p>
2026-08-22T17:21:37.617Z
<p dir="auto">Carlos, this is because <strong>Association Authentication Level</strong> and <strong>Object Attribute Access Rights</strong> are two decoupled security layers in DLMS/COSEM.</p>
<p dir="auto">Per <strong>DLMS Blue Book Ed. 17 Section 4.5.3 (Association LN Class 15)</strong> and <strong>IEC 62056-62 Section 6.2.23</strong>:<br />
The <code>Association LN</code> object (OBIS <code>0.0.40.0.0.255</code>) contains Attribute 2 <code>object_list</code>, which defines an access descriptor table for every object accessible under that client SAP:</p>
<pre><code class="language-text">ObjectAccessDescriptor ::= Structure {
class_id: Long-Unsigned,
logical_name: Octet-String (6B),
access_rights: Structure {
attribute_access_modes: Array [
{ attribute_id: 2, access_mode: Enum }
],
method_access_modes: Array [
{ method_id: 1, access_mode: Enum }
]
}
}
</code></pre>
<h3>Access Mode Enumeration (IEC 62056-62 Table 42):</h3>
<ul>
<li><code>0</code> = <code>no_access</code></li>
<li><code>1</code> = <code>read_only</code> (Plaintext allowed)</li>
<li><code>2</code> = <code>write_only</code></li>
<li><code>3</code> = <code>read_and_write</code></li>
<li><code>4</code> = <strong><code>authenticated_read</code></strong></li>
<li><code>5</code> = <strong><code>authenticated_and_encrypted_read</code></strong></li>
</ul>
<p dir="auto">For energy registers (Class 3), the access mode is often set to <code>1</code> (<code>read_only</code>).<br />
For Clock (Class <img src="https://dlms.sharur.org/assets/plugins/nodebb-plugin-emoji/emoji/android/1f60e.png?v=666d1e6b6e4" class="not-responsive emoji emoji-android emoji--sunglasses" style="height:23px;width:auto;vertical-align:middle" title="8)" alt="đ" /> and Disconnect Control (Class 70), the access mode is configured as <code>5</code> (<strong><code>authenticated_and_encrypted</code></strong>). When you transmit a plain <code>0xC0 0x01</code> APDU, the meter enforces rule 5 and rejects with <code>scope-of-access-violated</code>!</p>
2026-08-22T17:21:25.597Z
<p dir="auto">Notice how clean this is: GBT operates as a transport bridge below the COSEM APDU, allowing full backward compatibility with any COSEM object.</p>
2026-08-22T17:21:11.892Z
<p dir="auto">Let's compare the efficiency of GBT vs Traditional DataBlocks:</p>
<ol>
<li><strong>Traditional DataBlock (<code>0xC4 0x02</code>)</strong>:
<ul>
<li>Strictly 1-by-1 stop-and-wait.</li>
<li>For every 1024-byte block, HES must send <code>Get-Request-Next</code> (<code>0xC0 0x02</code>). Over cellular LTE-M with 200ms latency, transferring 500 KB takes 100+ seconds!</li>
</ul>
</li>
<li><strong>General Block Transfer (GBT)</strong>:
<ul>
<li>Supports <strong>Sliding Window Streaming</strong> (e.g. Window Size = 4).</li>
<li>Meter streams 4 consecutive blocks before requiring a single GBT ACK from HES, cutting transfer time by 75%!</li>
</ul>
</li>
</ol>
<p dir="auto">However, if the HES stack does not implement the GBT state machine, communication deadlocks immediately.</p>
2026-08-22T17:20:56.124Z
<p dir="auto">Here is the verified <code>Action-Response-Normal</code> from Method 3 indicating verification success:</p>
<pre><code class="language-hex">00 01 00 01 00 01 00 07 C7 01 C1 00 00
</code></pre>
<ul>
<li><code>C7 01</code>: <code>Action-Response-Normal</code></li>
<li><code>C1</code>: Invoke-ID 1</li>
<li><code>00</code>: Result <code>success</code> (verification initiated)</li>
</ul>
<p dir="auto">Reading Attribute 6 (<code>image_transfer_status</code>) returns <code>0x03</code> (<code>verification_successful</code>).</p>
2026-08-22T17:20:44.668Z
<p dir="auto">Let's check Attribute 3 (<code>image_transferred_blocks_status</code>) and Attribute 4 (<code>image_first_not_transferred_block_number</code>).</p>
<p dir="auto">Per <strong>DLMS Blue Book Ed. 17 Section 4.3.8 Table 19</strong>:</p>
<ul>
<li>Attribute 3 is a <code>Bit-String</code> where bit $i = 1$ indicates block $i$ has been received.</li>
<li><strong>Zero-Based vs One-Based Indexing</strong>:<br />
In DLMS, block numbers in <code>image_block_transfer</code> are <strong>0-indexed</strong> (<code>block_number: 0</code> to <code>block_number: N-1</code>).<br />
If your HES sent block numbers starting from <code>1</code> up to <code>980</code>, block <code>0</code> was never transferred!<br />
Attribute 4 would report <code>image_first_not_transferred_block_number = 0</code>, causing Method 3 <code>image_verify</code> to fail instantly because the image is incomplete!</li>
</ul>