From d62616a9f62d4956d7ba1a754bc931bb5688ed33 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:12:47 +0100 Subject: [PATCH] Matter update Interaction Model revision (#24441) --- .../SPEC_VS_IMPLEMENTATION_ANALYSIS.md | 366 ++++++++++++++++++ .../berry_matter/src/embedded/Matter_IM.be | 12 +- .../src/embedded/Matter_IM_Data.be | 7 +- .../src/embedded/Matter_IM_Message.be | 2 +- .../src/solidify/solidified_Matter_IM.h | 2 +- .../src/solidify/solidified_Matter_IM_Data.h | 30 +- .../solidify/solidified_Matter_IM_Message.h | 2 +- 7 files changed, 399 insertions(+), 22 deletions(-) create mode 100644 lib/libesp32/berry_matter/specs_for_ai/SPEC_VS_IMPLEMENTATION_ANALYSIS.md diff --git a/lib/libesp32/berry_matter/specs_for_ai/SPEC_VS_IMPLEMENTATION_ANALYSIS.md b/lib/libesp32/berry_matter/specs_for_ai/SPEC_VS_IMPLEMENTATION_ANALYSIS.md new file mode 100644 index 000000000..38429769e --- /dev/null +++ b/lib/libesp32/berry_matter/specs_for_ai/SPEC_VS_IMPLEMENTATION_ANALYSIS.md @@ -0,0 +1,366 @@ +# Matter 1.4.1 Spec vs Tasmota Implementation — Gap Analysis & Change Spec + +## 1. Executive Summary + +This document compares the Matter 1.4.1 Core Specification (March 2025) against the current Tasmota Berry implementation across the message layer, commissioning (PASE/CASE), and Interaction Model. The implementation is solid and functionally correct for a resource-constrained device. The gaps identified are primarily around **session parameter negotiation** (new mandatory fields in 1.4), **InteractionModelRevision** being outdated, and a few minor protocol conformance items. No architectural changes are recommended — the current layered design is clean and appropriate for the platform. + +--- + +## 2. Layer-by-Layer Analysis + +### 2.1 Message Layer (`Matter_Message.be`) + +#### What matches the spec well: +- Message header encoding/decoding (flags, DSIZ, session ID, message counter, source/dest node IDs) — correct per §4.4 +- Security flags (P, C, MX, SessionType) — correctly parsed +- Protocol header (exchange flags I/A/R/SX/V, opcode, exchange ID, protocol ID, vendor ID, ack counter) — correct per §4.4 +- Nonce construction for encryption/decryption (SecurityFlags || MessageCounter || SourceNodeID, 13 bytes) — correct per §4.7 +- AES-128-CCM encryption/decryption with 16-byte MIC — correct per §4.7 +- Privacy flag handling with AES-CTR decryption — present (§4.8) +- Message version check (bits 3-7 of flags must be 0x00 for Matter 1.0) — correct + +#### Gaps: +| # | Gap | Spec Reference | Severity | Notes | +|---|-----|---------------|----------|-------| +| M1 | Privacy encryption nonce uses `session_id` in big-endian but spec says little-endian for the 2-byte session ID in the privacy nonce | §4.8 | Low | The privacy nonce is `SessionID(2) || MIC[0..10]`. Current code uses `self.local_session_id` with `-2` (big-endian). Should verify byte order. | +| M2 | Message Extensions (MX flag) are skipped but never generated | §4.4 | None | Correct behavior for a device that doesn't use MX. Parsing correctly skips them. | +| M3 | Secured Extensions (SX flag) are skipped but never generated | §4.4 | None | Same as above, correct. | + +**Verdict: Message layer is spec-compliant. No changes needed.** + +--- + +### 2.2 Message Handler (`Matter_MessageHandler.be`) + +#### What matches the spec well: +- Dispatches unencrypted (session_id=0, sesstype=0) to commissioning — correct +- Dispatches encrypted messages by looking up session via `local_session_id` — correct +- Protocol ID routing: 0x0000 → Secure Channel, 0x0001 → Interaction Model — correct per §4.5 +- Duplicate message detection using counter validation — correct per §4.6 +- MRP standalone acknowledgement handling (opcode 0x10) — correct per §4.9 +- Control message (sec_p flag) routing — present + +#### Gaps: +| # | Gap | Spec Reference | Severity | Notes | +|---|-----|---------------|----------|-------| +| MH1 | BDX (protocol 0x0002) and UDC (protocol 0x0003) are commented out | §4.5 | None | Intentional — BDX is for OTA file transfer, UDC is for commissioner devices. Neither is needed for a basic Matter device. | +| MH2 | No MCSP (Message Counter Synchronization Protocol, opcode 0x00/0x01) handling | §4.6 | Low | MCSP is needed for group messaging counter sync. Since Tasmota doesn't support group messaging, this is acceptable. | + +**Verdict: Message handler is correct. No changes needed.** + +--- + +### 2.3 Commissioning — PASE (`Matter_Commissioning_Context.be`, `Matter_Commissioning_Data.be`) + +#### What matches the spec well: +- PBKDFParamRequest parsing (tag 1=initiatorRandom, 2=initiatorSessionId, 3=passcodeId, 4=hasPBKDFParameters, 5=sessionParams) — correct per §4.11 +- PBKDFParamResponse generation (tag 1=initiatorRandom, 2=responderRandom, 3=responderSessionId, 4=pbkdf_parameters) — correct per §4.11 +- SPAKE2+ computation with Matter variant context prefix "CHIP PAKE V1 Commissioning" — correct +- Pake1/Pake2/Pake3 message flow — correct per §4.11 +- Session key derivation: `HKDF(Ke, [], "SessionKeys", 48)` → I2R || R2I || AC — correct per §4.11 +- StatusReport for PakeFinished — correct +- PBKDF iterations (1000) within spec range (1000-100000) — correct per §3.1 +- Salt generation (16 bytes random) within spec range (16-32) — correct per §3.4 +- Passcode validation (invalid passcodes list) — correct per §5.1 + +#### Gaps: +| # | Gap | Spec Reference | Severity | Notes | +|---|-----|---------------|----------|-------| +| P1 | **Session parameter struct in PBKDFParamResponse only sends SII/SAI (tags 1,2), missing mandatory fields: DATA_MODEL_REVISION (tag 4), INTERACTION_MODEL_REVISION (tag 5), SPECIFICATION_VERSION (tag 6), MAX_PATHS_PER_INVOKE (tag 7)** | §4.10 | **HIGH** | Matter 1.4 made these fields mandatory in the session-parameter-struct. The current implementation only sends SLEEPY_IDLE_INTERVAL and SLEEPY_ACTIVE_INTERVAL. Modern controllers may expect these fields. | +| P2 | PBKDFParamRequest parsing doesn't extract new session parameter fields from initiator | §4.10 | Medium | Should parse and potentially use DATA_MODEL_REVISION, SPECIFICATION_VERSION etc. from the initiator for compatibility negotiation. | +| P3 | SESSION_ACTIVE_THRESHOLD (tag 3, uint16) not sent in session params | §4.10 | Medium | Default is 4000ms per spec. Should be included. | + +--- + +### 2.4 Commissioning — CASE (`Matter_Commissioning_Context.be`) + +#### What matches the spec well: +- Sigma1 parsing (initiatorRandom, initiatorSessionId, destinationId, initiatorEphPubKey, resumptionID, initiatorResumeMIC) — correct per §4.12 +- Destination Identifier computation: `HMAC(IPK, initiatorRandom || rootPublicKey || fabricId || nodeId)` — correct per §4.12 +- Sigma2 generation with TBSData2 and TBEData2 — correct per §4.12 +- S2K derivation: `HKDF(SharedSecret, IPK||ResponderRandom||ResponderEphPubKey||TranscriptHash, "Sigma2", 16)` — correct +- S3K derivation: `HKDF(SharedSecret, IPK||TranscriptHash, "Sigma3", 16)` — correct +- TBEData2/3 nonces: "NCASE_Sigma2N" / "NCASE_Sigma3N" — correct per §4.12 +- Session key derivation: `HKDF(SharedSecret, IPK||TranscriptHash, "SessionKeys", 48)` — correct +- CASE Resumption flow (S1RK, S2RK, Resume1MIC, Resume2MIC) — correct per §4.12 +- Resumption session keys: `HKDF(SharedSecret, initiatorRandom||ResumptionID, "SessionResumptionKeys", 48)` — correct +- Resume nonces: "NCASE_SigmaS1" / "NCASE_SigmaS2" — correct + +#### Gaps: +| # | Gap | Spec Reference | Severity | Notes | +|---|-----|---------------|----------|-------| +| C1 | **Sigma2 and Sigma2Resume don't include responderSessionParams with mandatory fields** | §4.10, §4.12 | **HIGH** | Same as P1 — the session-parameter-struct with DATA_MODEL_REVISION, INTERACTION_MODEL_REVISION, SPECIFICATION_VERSION, MAX_PATHS_PER_INVOKE must be sent. | +| C2 | Sigma3 validation doesn't verify NOC chain back to TrustedRCAC | §4.12 | Medium | There's a TODO comment in the code. The NOC signature is verified, but the full certificate chain validation (NOC → ICAC → RCAC) is not performed. This is a known shortcut. | +| C3 | Sigma3 doesn't verify that the Fabric ID in the initiator's NOC matches the session's fabric | §4.12 | Medium | The code extracts `initiatorFabricId` but doesn't compare it against the session's fabric ID. | +| C4 | SUPPORTED_TRANSPORTS (tag 8) not sent in session params | §4.10 | Low | Optional but useful for indicating UDP-only support. | + +--- + +### 2.5 Commissioning — mDNS Discovery (`Matter_z_Commissioning.be`) + +#### What matches the spec well: +- Commissionable discovery: `_matterc._udp` service type — correct per §4.3.1 +- Random 16-char hex instance name — correct per §4.3.1 +- TXT records: D (discriminator), VP (vendor+product), CM (commissioning mode), T (TCP support) — correct +- Subtypes: `_L`, `_S`, `_V`, `_CM1` — correct per §4.3.1 +- Operational discovery: `_matter._tcp` with `-` instance — correct per §4.3.2 +- SII=500, SAI=300 defaults — correct per §4.10 +- Port 5540 — correct per §2.4 + +#### Gaps: +| # | Gap | Spec Reference | Severity | Notes | +|---|-----|---------------|----------|-------| +| D1 | Operational discovery TXT records don't include SII, SAI, SAT, T, ICD keys | §4.3.2 | Low | For an always-on WiFi device, these are optional but recommended. The `T` key (TCP support bitmap) should be 0. | +| D2 | No `_T` subtype in commissionable discovery | §4.3.1 | Low | Optional but useful for filtering. | +| D3 | `DN` (device name) TXT record not included in commissionable discovery | §4.3.1 | Low | Optional. | + +--- + +### 2.6 Interaction Model (`Matter_IM.be`, `Matter_IM_Message.be`, `Matter_IM_Data.be`) + +#### What matches the spec well: +- All IM opcodes handled: StatusResponse(0x01), ReadRequest(0x02), SubscribeRequest(0x03), SubscribeResponse(0x04), ReportData(0x05), WriteRequest(0x06), WriteResponse(0x07), InvokeRequest(0x08), InvokeResponse(0x09), TimedRequest(0x0A) — correct per §8.4 +- ReadRequestMessage structure (AttributeRequests, EventRequests, EventFilters, FabricFiltered, DataVersionFilters) — correct per §8.5 +- ReportDataMessage structure (SubscriptionId, AttributeReports, EventReports, MoreChunkedMessages, SuppressResponse) — correct per §8.5 +- WriteRequestMessage/WriteResponseMessage — correct per §8.5 +- InvokeRequestMessage/InvokeResponseMessage — correct per §8.5 +- SubscribeRequestMessage/SubscribeResponseMessage — correct per §8.5 +- AttributePathIB encoding (endpoint/cluster/attribute/ListIndex) — correct per §8.2 +- Chunked message handling with MAX_MESSAGE=1150 (within 1280 MTU minus headers) — correct per §4.4.4 +- Subscription management with min/max intervals — correct +- Solo (fast-path) optimization for single attribute reads and single invoke requests — good optimization +- Event support with EventGenerator and event filtering — correct + +#### Gaps: +| # | Gap | Spec Reference | Severity | Notes | +|---|-----|---------------|----------|-------| +| IM1 | ~~**InteractionModelRevision = 11 (Matter 1.2)**. Matter 1.4 requires revision 12.~~ ✅ FIXED | §8.4 | ~~**HIGH**~~ | Updated to 12 in all outgoing paths (TLV-based and raw-encoded). Also fixed incoming solo parser to accept any revision. | +| IM2 | TimedRequest handling sends SUCCESS but doesn't enforce timed interaction semantics | §8.4 | Medium | The `process_timed_request` method sends a success status but doesn't track the timed window. Subsequent Write/Invoke within the timeout should check `TimedRequest` flag. Currently `timed_request` field in WriteRequest/InvokeRequest is parsed but not validated. | +| IM3 | DataVersionFilters in ReadRequest are parsed but not used for filtering | §8.5 | Low | The spec says if a DataVersionFilter matches the current cluster data version, the cluster's attributes should be omitted from the response. This optimization is not implemented. | +| IM4 | No `PATHS_EXHAUSTED` (0xC8) status code handling when too many paths are requested | §8.3 | Low | The spec limits to 9 attribute paths and 10 event paths per request. No enforcement. | +| IM5 | Subscription max_interval is hardcoded to 60 seconds regardless of requested ceiling | IM_Subscription.be | Low | `max_interval = 60` is forced. The spec allows up to 3600s. This is a deliberate choice for responsiveness but limits battery-powered controller scenarios. | + +--- + +### 2.7 Cluster Revisions and Data Model + +#### What matches: +- DataModelRevision = 18 (Matter 1.3+, compatible with 1.4.1) — correct +- Basic Information cluster revision = 3 — correct for Matter 1.4.1 +- Descriptor cluster revision = 2 — correct +- Global attributes (0xFFF8-0xFFFD) handled — correct per §7.4 + +#### Gaps: +| # | Gap | Spec Reference | Severity | Notes | +|---|-----|---------------|----------|-------| +| CL1 | SpecificationVersion attribute (0x0015) in Basic Information cluster — need to verify it's set correctly | §11.1 | Medium | Should be `0x01040100` for Matter 1.4.1. | +| CL2 | MaxPathsPerInvoke attribute (0x0016) in Basic Information cluster — need to verify | §11.1 | Low | Should be 1 (single invoke path). | + +--- + +## 3. Architecture Assessment + +The current architecture is well-suited for the platform: + +``` +Matter_MessageHandler (dispatch) + ├── Matter_Commisioning_Context (PASE/CASE) + ├── Matter_IM (Interaction Model) + │ ├── Matter_IM_Message (response queue) + │ ├── Matter_IM_Subscription (subscription shop) + │ └── PathGenerator / EventGenerator (lazy evaluation) + └── Matter_Control_Message (MCSP) +``` + +**No architectural changes recommended.** The separation of concerns is clean: +- Message framing/crypto is isolated in `Matter_Frame` +- Session management is separate from message handling +- IM has a clean send queue with proper exchange tracking +- The "solo" fast-path optimization for single reads/invokes is a smart performance choice +- Lazy (pull) evaluation of attributes during ReportData generation is memory-efficient + +--- + +## 4. Recommended Changes — Detailed Specification + +### Change 1: Add Mandatory Session Parameters (HIGH Priority) + +**Files affected:** `Matter_Commissioning_Data.be`, `Matter_Commissioning_Context.be` + +**Rationale:** Matter 1.4 made several fields mandatory in the `session-parameter-struct` (tag 5 in PBKDFParamResponse, Sigma2, Sigma2Resume). Modern controllers (Apple Home, Google Home, Samsung SmartThings) may reject sessions that don't include these fields. + +**Spec reference:** §4.10 Session Parameter TLV + +**Current behavior:** Only `SESSION_IDLE_INTERVAL` (tag 1) and `SESSION_ACTIVE_INTERVAL` (tag 2) are conditionally sent. + +**Required behavior:** The responder session params struct must include: + +``` +session-parameter-struct => STRUCTURE [tag-order] { + SESSION_IDLE_INTERVAL [1, optional]: UNSIGNED INTEGER [32-bits], // 500 (ms) + SESSION_ACTIVE_INTERVAL [2, optional]: UNSIGNED INTEGER [32-bits], // 300 (ms) + SESSION_ACTIVE_THRESHOLD [3, optional]: UNSIGNED INTEGER [16-bits], // 4000 (ms) + DATA_MODEL_REVISION [4]: UNSIGNED INTEGER [16-bits], // 18 + INTERACTION_MODEL_REVISION [5]: UNSIGNED INTEGER [16-bits], // 12 + SPECIFICATION_VERSION [6]: UNSIGNED INTEGER [32-bits], // 0x01040100 + MAX_PATHS_PER_INVOKE [7]: UNSIGNED INTEGER [16-bits], // 1 +} +``` + +**Implementation plan:** + +1. In `Matter_PBKDFParamResponse.tlv2raw()`: Always generate the session params struct (tag 5) with all mandatory fields. + +2. In `Matter_Sigma2.tlv2raw()`: Always generate the session params struct (tag 5) with all mandatory fields. + +3. In `Matter_Sigma2Resume.tlv2raw()`: Always generate the session params struct (tag 4) with all mandatory fields. + +4. Define constants in a central location (e.g., `matter` module or a static in the commissioning class): + - `DATA_MODEL_REVISION = 18` + - `INTERACTION_MODEL_REVISION = 12` + - `SPECIFICATION_VERSION = 0x01040100` (1.4.1.0) + - `MAX_PATHS_PER_INVOKE = 1` + +**Example code change for `Matter_PBKDFParamResponse.tlv2raw()`:** +```berry +def tlv2raw(b) + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(1, TLV.B1, self.initiatorRandom) + s.add_TLV(2, TLV.B1, self.responderRandom) + s.add_TLV(3, TLV.U2, self.responderSessionId) + var s_pbkdf = s.add_struct(4) + s_pbkdf.add_TLV(1, TLV.U4, self.pbkdf_parameters_iterations) + s_pbkdf.add_TLV(2, TLV.B1, self.pbkdf_parameters_salt) + # Always include session params with mandatory fields + var s2 = s.add_struct(5) + s2.add_TLV(1, TLV.U4, 500) # SESSION_IDLE_INTERVAL + s2.add_TLV(2, TLV.U4, 300) # SESSION_ACTIVE_INTERVAL + s2.add_TLV(3, TLV.U2, 4000) # SESSION_ACTIVE_THRESHOLD + s2.add_TLV(4, TLV.U2, 18) # DATA_MODEL_REVISION + s2.add_TLV(5, TLV.U2, 12) # INTERACTION_MODEL_REVISION + s2.add_TLV(6, TLV.U4, 0x01040100) # SPECIFICATION_VERSION (1.4.1.0) + s2.add_TLV(7, TLV.U2, 1) # MAX_PATHS_PER_INVOKE + return s.tlv2raw(b) +end +``` + +--- + +### Change 2: Update InteractionModelRevision to 12 ~~(HIGH Priority)~~ ✅ DONE + +**Files changed:** `Matter_IM_Data.be`, `Matter_IM_Message.be`, `Matter_IM.be` + +**What was done:** +- `Matter_IM_Data.be`: `InteractionModelRevision` set to `12` (was `11`). Also fixed `InvokeRequestMessage_solo.from_raw()` to accept any IM revision value from incoming messages instead of hardcoding `0x24FF0118`. +- `Matter_IM_Message.be`: Raw-encoded IM revision in `ReportData_Pull.send_im()` changed from `0x01` to `12` (0x0C). +- `Matter_IM.be`: Three raw-encoded suffixes in solo fast-paths changed from `0x1824FF01` to `0x1824FF0C` — covering `process_read_request_solo` (two paths: success and error) and `process_invoke_request_solo`. + +--- + +### Change 3: Timed Interaction Enforcement (MEDIUM Priority) + +**Files affected:** `Matter_IM.be` + +**Rationale:** The current implementation accepts TimedRequest and returns SUCCESS, but doesn't track the timed window. A subsequent Write or Invoke with `timed_request=true` should only succeed if a TimedRequest was received within the timeout window on the same exchange. + +**Spec reference:** §8.4, §8.5 + +**Implementation plan:** + +1. In `process_timed_request()`: Store the exchange_id and expiration time (`tasmota.millis() + timeout_ms`). + +2. In `process_write_request()` and `process_invoke_request()`: If `query.timed_request == true`, verify that a matching timed request exists and hasn't expired. If not, return `TIMED_REQUEST_MISMATCH` (0xC9). + +3. If `query.timed_request == false` but the operation requires a timed interaction (e.g., certain cluster commands), return `NEEDS_TIMED_INTERACTION` (0xC6). + +**Suggested data structure:** +```berry +# In Matter_IM class +var timed_exchanges # map: exchange_id -> expiration_millis + +def process_timed_request(msg, val) + var query = matter.TimedRequestMessage().from_TLV(val) + if self.timed_exchanges == nil self.timed_exchanges = {} end + self.timed_exchanges[msg.exchange_id] = tasmota.millis() + query.timeout + self.send_status(msg, matter.SUCCESS) + return true +end + +def check_timed_interaction(msg, is_timed_request) + if !is_timed_request return true end # not a timed request, ok + if self.timed_exchanges == nil return false end + var expiry = self.timed_exchanges.find(msg.exchange_id) + self.timed_exchanges.remove(msg.exchange_id) # one-shot + if expiry == nil return false end + return !tasmota.time_reached(expiry) +end +``` + +--- + +### Change 4: Certificate Chain Validation in Sigma3 (MEDIUM Priority) + +**Files affected:** `Matter_Commissioning_Context.be` + +**Rationale:** The code has a TODO comment about verifying the NOC chain. While the signature is verified, the full chain (NOC → optional ICAC → RCAC) is not validated. This is a security gap. + +**Spec reference:** §4.12 (Sigma3 Validation step 2) + +**Implementation plan:** + +1. After decrypting TBEData3, extract `initiatorNOC` and `initiatorICAC`. +2. Verify that `initiatorNOC` is signed by `initiatorICAC` (if present) or directly by the trusted RCAC. +3. Verify that `initiatorICAC` (if present) is signed by the trusted RCAC. +4. Verify that the Fabric ID in the NOC matches the session's fabric. +5. If any verification fails, send `StatusReport(FAILURE, SECURE_CHANNEL, INVALID_PARAMETER)`. + +This is complex to implement in Berry due to X.509/Matter certificate parsing requirements. A pragmatic approach would be to at least verify the Fabric ID match (gap C3). + +--- + +### Change 5: Operational Discovery TXT Records (LOW Priority) + +**Files affected:** `Matter_z_Commissioning.be` + +**Rationale:** Adding SII, SAI, T keys to operational discovery helps controllers optimize their retry behavior. + +**Spec reference:** §4.3.2 + +**Implementation plan:** + +In `mdns_announce_op_discovery()`, add TXT records: +```berry +var services = { + "SII": 500, # SESSION_IDLE_INTERVAL + "SAI": 300, # SESSION_ACTIVE_INTERVAL + "SAT": 4000, # SESSION_ACTIVE_THRESHOLD + "T": 0 # TCP support: 0 = no TCP +} +mdns.add_service("_matter", "_tcp", 5540, services, op_node, hostname) +``` + +--- + +## 5. Priority Summary + +| Priority | Change | Impact | Effort | +|----------|--------|--------|--------| +| **HIGH** | Session parameter struct with mandatory fields (Change 1) | Compatibility with modern controllers | Medium | +| **HIGH** | ~~InteractionModelRevision = 12 (Change 2)~~ ✅ DONE | Spec compliance, controller compatibility | Trivial | +| MEDIUM | Timed interaction enforcement (Change 3) | Security compliance | Low | +| MEDIUM | Certificate chain validation (Change 4) | Security | High | +| LOW | Operational discovery TXT records (Change 5) | Better MRP behavior | Trivial | + +--- + +## 6. What NOT to Change + +- **Architecture**: The current layered design is clean and appropriate. No refactoring needed. +- **Solo fast-path**: The optimization for single reads/invokes is valuable on constrained hardware. Keep it. +- **Pull-mode ReportData**: Lazy attribute evaluation is memory-efficient. Keep it. +- **BDX/UDC**: Not needed for a basic Matter device. Keep them disabled. +- **Group messaging**: Not needed for typical Tasmota use cases. Keep it unimplemented. +- **TCP transport**: Not needed for a UDP-only device. Keep it unimplemented. +- **MAX_MESSAGE = 1150**: This is a good conservative value within the 1280 MTU limit. +- **Subscription max_interval = 60s**: This is a deliberate trade-off for responsiveness. Acceptable. diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be index b75c9509a..685b57192 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be @@ -787,8 +787,8 @@ class Matter_IM self.attributedata2raw(raw, ctx, res) - # add suffix 1824FF0118 - raw.add(0x1824FF01, -4) # add 1824FF01 + # add suffix 1824FF0C18 + raw.add(0x1824FF0C, -4) # add 1824FF0C - InteractionModelRevision 12 raw.add(0x18, 1) # add 18 elif ctx.status != nil @@ -801,8 +801,8 @@ class Matter_IM self.attributestatus2raw(raw, ctx, ctx.status) - # add suffix 1824FF0118 - raw.add(0x1824FF01, -4) # add 1824FF01 + # add suffix 1824FF0C18 + raw.add(0x1824FF0C, -4) # add 1824FF0C - InteractionModelRevision 12 raw.add(0x18, 1) # add 18 else @@ -1022,8 +1022,8 @@ class Matter_IM # ignore if content is nil and status is undefined return false end - # add suffix 1824FF0118 - raw.add(0x1824FF01, -4) # add 1824FF01 + # add suffix 1824FF0C18 + raw.add(0x1824FF0C, -4) # add 1824FF0C - InteractionModelRevision 12 raw.add(0x18, 1) # add 18 # log(f"MTR: raw={raw.tohex()}", 3) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be index 797b7e5ac..6f3d44970 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be @@ -566,7 +566,7 @@ class Matter_IM_Message_base : Matter_IM_base var InteractionModelRevision # 0xFF def init() - self.InteractionModelRevision = 11 # 11 = Matter 1.2+ Interaction Model revision + self.InteractionModelRevision = 12 # 12 = Matter 1.4+ Interaction Model revision end end @@ -811,7 +811,10 @@ class Matter_InvokeRequestMessage_solo : Matter_Path # close if raw.get(idx, -2) != 0x1818 return nil end idx += 2 - if raw.get(idx, -4) != 0x24FF0118 return nil end + # skip 24FFxx (InteractionModelRevision, any value) + if raw.get(idx, -2) == 0x24FF idx += 3 end + # expect 18 + if raw.get(idx, 1) != 0x18 return nil end # all good return self diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM_Message.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Message.be index f19fe20bd..445bb7de1 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_IM_Message.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Message.be @@ -391,7 +391,7 @@ class Matter_IM_ReportData_Pull : Matter_IM_Message end # InteractionModelRevision raw.add(0x24FF, -2) # add 24FF - raw.add(0x01, 1) # add 01 + raw.add(0x0C, 1) # add 0C - InteractionModelRevision 12 (Matter 1.4+) # close struct ReportDataMessage raw.add(0x18, 1) # add 18 # log(f">>>: {raw.tohex()}", 3) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h index 2f3817b58..251059d8f 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h @@ -150,7 +150,7 @@ static const bvalue be_ktab_class_Matter_IM[203] = { /* K141 */ be_nested_str_weak(expire_sendqueue), /* K142 */ be_nested_str_weak(MTR_X3A_X20_X3ECommand1_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s_X20_X25s), /* K143 */ be_const_int(354943030), - /* K144 */ be_const_int(405077761), + /* K144 */ be_const_int(405077772), /* K145 */ be_nested_str_weak(build_response), /* K146 */ be_nested_str_weak(message_handler), /* K147 */ be_nested_str_weak(raw), diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h index dd2e64735..a17814e6f 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h @@ -185,7 +185,7 @@ be_local_closure(class_Matter_IM_Message_base_init, /* name */ be_str_weak(init), &be_const_str_solidified, ( &(const binstruction[ 3]) { /* code */ - 0x5406000A, // 0000 LDINT R1 11 + 0x5406000B, // 0000 LDINT R1 12 0x90020001, // 0001 SETMBR R0 K0 R1 0x80000000, // 0002 RET 0 }) @@ -3286,8 +3286,8 @@ be_local_class(Matter_InvokeRequestMessage, })), be_str_weak(Matter_InvokeRequestMessage) ); -// compact class 'Matter_InvokeRequestMessage_solo' ktab size: 17, total: 20 (saved 24 bytes) -static const bvalue be_ktab_class_Matter_InvokeRequestMessage_solo[17] = { +// compact class 'Matter_InvokeRequestMessage_solo' ktab size: 16, total: 19 (saved 24 bytes) +static const bvalue be_ktab_class_Matter_InvokeRequestMessage_solo[16] = { /* K0 */ be_nested_str_weak(reset), /* K1 */ be_nested_str_weak(SuppressResponse), /* K2 */ be_nested_str_weak(TimedRequest), @@ -3304,7 +3304,6 @@ static const bvalue be_ktab_class_Matter_InvokeRequestMessage_solo[17] = { /* K13 */ be_nested_str_weak(TLV), /* K14 */ be_nested_str_weak(parse), /* K15 */ be_nested_str_weak(next_idx), - /* K16 */ be_const_int(620691736), }; @@ -3359,7 +3358,7 @@ be_local_closure(class_Matter_InvokeRequestMessage_solo_from_raw, /* name */ &be_ktab_class_Matter_InvokeRequestMessage_solo, /* shared constants */ be_str_weak(from_raw), &be_const_str_solidified, - ( &(const binstruction[170]) { /* code */ + ( &(const binstruction[179]) { /* code */ 0x8C0C0100, // 0000 GETMET R3 R0 K0 0x7C0C0200, // 0001 CALL R3 1 0x600C000C, // 0002 GETGBL R3 G12 @@ -3523,13 +3522,22 @@ be_local_closure(class_Matter_InvokeRequestMessage_solo_from_raw, /* name */ 0x00080506, // 00A0 ADD R2 R2 K6 0x8C140304, // 00A1 GETMET R5 R1 K4 0x5C1C0400, // 00A2 MOVE R7 R2 - 0x5421FFFB, // 00A3 LDINT R8 -4 + 0x5421FFFD, // 00A3 LDINT R8 -2 0x7C140600, // 00A4 CALL R5 3 - 0x20140B10, // 00A5 NE R5 R5 K16 - 0x78160001, // 00A6 JMPF R5 #00A9 - 0x4C140000, // 00A7 LDNIL R5 - 0x80040A00, // 00A8 RET 1 R5 - 0x80040000, // 00A9 RET 1 R0 + 0x541A24FE, // 00A5 LDINT R6 9471 + 0x1C140A06, // 00A6 EQ R5 R5 R6 + 0x78160000, // 00A7 JMPF R5 #00A9 + 0x00080507, // 00A8 ADD R2 R2 K7 + 0x8C140304, // 00A9 GETMET R5 R1 K4 + 0x5C1C0400, // 00AA MOVE R7 R2 + 0x58200005, // 00AB LDCONST R8 K5 + 0x7C140600, // 00AC CALL R5 3 + 0x541A0017, // 00AD LDINT R6 24 + 0x20140A06, // 00AE NE R5 R5 R6 + 0x78160001, // 00AF JMPF R5 #00B2 + 0x4C140000, // 00B0 LDNIL R5 + 0x80040A00, // 00B1 RET 1 R5 + 0x80040000, // 00B2 RET 1 R0 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Message.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Message.h index 6a0337ed1..0878959c8 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Message.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Message.h @@ -929,7 +929,7 @@ be_local_closure(class_Matter_IM_ReportData_Pull_send_im, /* name */ 0x5431FFFD, // 014E LDINT R12 -2 0x7C240600, // 014F CALL R9 3 0x8C241123, // 0150 GETMET R9 R8 K35 - 0x582C0024, // 0151 LDCONST R11 K36 + 0x542E000B, // 0151 LDINT R11 12 0x58300024, // 0152 LDCONST R12 K36 0x7C240600, // 0153 CALL R9 3 0x8C241123, // 0154 GETMET R9 R8 K35