Matter simplify TLV type with generalized integers (#25087)

This commit is contained in:
s-hadinger authored and GitHub committed 2026-09-29 14:36:02 +02:00
1 parent 835813e423
commit 1f543a3374
27 files changed
+244 -208

No files matched your search

+34
View File
@@ -62,6 +62,40 @@ solidified during the Tasmota build. Do not require generated files in
`src/solidify/` to be updated in a pull request unless the build workflow
explicitly requires committed generated output.
### Berry Matter TLV encoding widths
When encoding, `Matter_TLV_item.tlv2raw()` and `encode_len()` in
`lib/libesp32/berry_matter/src/embedded/Matter_TLV.be` choose the wire type
from the value. The type passed to `add_TLV()` / `set()` is only a starting
point:
- `I2`/`I4` shrink to the smallest signed width that fits (`I1`, `I2` or `I4`).
- `U2`/`U4` shrink to the smallest unsigned width that fits (`U1`, `U2` or `U4`).
A Berry int that is negative, meaning a u32 above `0x7FFFFFFF`, stays `U4`.
- `I8`/`U8` with a plain Berry `int` become `I4`/`U4`, then shrink further.
An `int64` instance or `bytes(8)` is always written as 8 bytes, even when
the value is small. Pass an `int` if you want the compact form.
- `I1`/`U1` are never widened. A value that doesn't fit is truncated to one
byte, so declare a wider type if the value can exceed the range.
- Signedness is kept: `U*` never becomes `I*`, and the reverse is also true.
- `B1`..`B8` and `UTF1`..`UTF8` get their length prefix from the actual size.
`BOOL` becomes `BTRUE` or `BFALSE` from the value.
- Encoding updates `item.typ` in place.
Convention: Matter Berry code encodes every signed integer up to 32 bits as
`0x02 #-TLV.I4-#` and every unsigned one as `0x06 #-TLV.U4-#`, whatever the
schema width (enum8, uint16, int16, and so on). Don't use `I1`/`I2`/`U1`/`U2`
in new code. `I8`/`U8` stay for 64-bit fields, and the other type codes are
unchanged. `Matter_zzz_TLV_test.be` still covers every code to test the
encoder.
As a result, declaring `U1`, `U2` or `U4` for an enum8, or `I8` for an int64
field holding a small value, produces the same bytes. Matter TLV readers must accept
any integer width that holds the value, so code reviews shouldn't flag the
declared width unless it is too narrow (`I1`/`U1` truncation) or an `int64`
instance is used where the compact form was expected. When decoding, only
8-byte integers come back as `int64`; smaller ones come back as Berry `int`.
### Configuration Override
To customize a build, copy `tasmota/user_config_override_sample.h` to `tasmota/user_config_override.h` and add your `#define` / `#undef` directives there. Do not edit `my_user_config.h` directly — it is the master configuration shipped with each release.
@@ -90,7 +90,7 @@ class Matter_PBKDFParamResponse
# initiatorRandom
s.add_TLV(1, 0x10 #-TLV.B1-#, self.initiatorRandom)
s.add_TLV(2, 0x10 #-TLV.B1-#, self.responderRandom)
s.add_TLV(3, 0x05 #-TLV.U2-#, self.responderSessionId)
s.add_TLV(3, 0x06 #-TLV.U4-#, self.responderSessionId)
var s_pbkdf = s.add_struct(4)
s_pbkdf.add_TLV(1, 0x06 #-TLV.U4-#, self.pbkdf_parameters_iterations)
s_pbkdf.add_TLV(2, 0x10 #-TLV.B1-#, self.pbkdf_parameters_salt)
@@ -98,11 +98,11 @@ class Matter_PBKDFParamResponse
var s2 = s.add_struct(5)
s2.add_TLV(1, 0x06 #-TLV.U4-#, self.SLEEPY_IDLE_INTERVAL) # SESSION_IDLE_INTERVAL (optional, sent if set)
s2.add_TLV(2, 0x06 #-TLV.U4-#, self.SLEEPY_ACTIVE_INTERVAL) # SESSION_ACTIVE_INTERVAL (optional, sent if set)
s2.add_TLV(3, 0x05 #-TLV.U2-#, 4000) # SESSION_ACTIVE_THRESHOLD (4000ms default)
s2.add_TLV(4, 0x05 #-TLV.U2-#, 21) # DATA_MODEL_REVISION
s2.add_TLV(5, 0x05 #-TLV.U2-#, 13) # INTERACTION_MODEL_REVISION
s2.add_TLV(3, 0x06 #-TLV.U4-#, 4000) # SESSION_ACTIVE_THRESHOLD (4000ms default)
s2.add_TLV(4, 0x06 #-TLV.U4-#, 21) # DATA_MODEL_REVISION
s2.add_TLV(5, 0x06 #-TLV.U4-#, 13) # INTERACTION_MODEL_REVISION
s2.add_TLV(6, 0x06 #-TLV.U4-#, 0x01060100) # SPECIFICATION_VERSION (1.6.1.0)
s2.add_TLV(7, 0x05 #-TLV.U2-#, 1) # MAX_PATHS_PER_INVOKE
s2.add_TLV(7, 0x06 #-TLV.U4-#, 1) # MAX_PATHS_PER_INVOKE
return s.tlv2raw(b)
end
end
@@ -224,18 +224,18 @@ class Matter_Sigma2
var s = TLV.Matter_TLV_struct()
# initiatorRandom
s.add_TLV(1, 0x10 #-TLV.B1-#, self.responderRandom)
s.add_TLV(2, 0x05 #-TLV.U2-#, self.responderSessionId)
s.add_TLV(2, 0x06 #-TLV.U4-#, self.responderSessionId)
s.add_TLV(3, 0x10 #-TLV.B1-#, self.responderEphPubKey)
s.add_TLV(4, 0x10 #-TLV.B1-#, self.encrypted2)
# Always include session params with mandatory fields (Matter 1.4 §4.10)
var s2 = s.add_struct(5)
s2.add_TLV(1, 0x06 #-TLV.U4-#, self.SLEEPY_IDLE_INTERVAL) # SESSION_IDLE_INTERVAL (optional, sent if set)
s2.add_TLV(2, 0x06 #-TLV.U4-#, self.SLEEPY_ACTIVE_INTERVAL) # SESSION_ACTIVE_INTERVAL (optional, sent if set)
s2.add_TLV(3, 0x05 #-TLV.U2-#, 4000) # SESSION_ACTIVE_THRESHOLD (4000ms default)
s2.add_TLV(4, 0x05 #-TLV.U2-#, 21) # DATA_MODEL_REVISION
s2.add_TLV(5, 0x05 #-TLV.U2-#, 13) # INTERACTION_MODEL_REVISION
s2.add_TLV(3, 0x06 #-TLV.U4-#, 4000) # SESSION_ACTIVE_THRESHOLD (4000ms default)
s2.add_TLV(4, 0x06 #-TLV.U4-#, 21) # DATA_MODEL_REVISION
s2.add_TLV(5, 0x06 #-TLV.U4-#, 13) # INTERACTION_MODEL_REVISION
s2.add_TLV(6, 0x06 #-TLV.U4-#, 0x01060100) # SPECIFICATION_VERSION (1.6.1.0)
s2.add_TLV(7, 0x05 #-TLV.U2-#, 1) # MAX_PATHS_PER_INVOKE
s2.add_TLV(7, 0x06 #-TLV.U4-#, 1) # MAX_PATHS_PER_INVOKE
return s.tlv2raw(b)
end
end
@@ -257,16 +257,16 @@ class Matter_Sigma2Resume
# initiatorRandom
s.add_TLV(1, 0x10 #-TLV.B1-#, self.resumptionID)
s.add_TLV(2, 0x10 #-TLV.B1-#, self.sigma2ResumeMIC)
s.add_TLV(3, 0x05 #-TLV.U2-#, self.responderSessionID)
s.add_TLV(3, 0x06 #-TLV.U4-#, self.responderSessionID)
# Always include session params with mandatory fields (Matter 1.4 §4.10)
var s2 = s.add_struct(4)
s2.add_TLV(1, 0x06 #-TLV.U4-#, self.SLEEPY_IDLE_INTERVAL) # SESSION_IDLE_INTERVAL (optional, sent if set)
s2.add_TLV(2, 0x06 #-TLV.U4-#, self.SLEEPY_ACTIVE_INTERVAL) # SESSION_ACTIVE_INTERVAL (optional, sent if set)
s2.add_TLV(3, 0x05 #-TLV.U2-#, 4000) # SESSION_ACTIVE_THRESHOLD (4000ms default)
s2.add_TLV(4, 0x05 #-TLV.U2-#, 21) # DATA_MODEL_REVISION
s2.add_TLV(5, 0x05 #-TLV.U2-#, 13) # INTERACTION_MODEL_REVISION
s2.add_TLV(3, 0x06 #-TLV.U4-#, 4000) # SESSION_ACTIVE_THRESHOLD (4000ms default)
s2.add_TLV(4, 0x06 #-TLV.U4-#, 21) # DATA_MODEL_REVISION
s2.add_TLV(5, 0x06 #-TLV.U4-#, 13) # INTERACTION_MODEL_REVISION
s2.add_TLV(6, 0x06 #-TLV.U4-#, 0x01060100) # SPECIFICATION_VERSION (1.6.1.0)
s2.add_TLV(7, 0x05 #-TLV.U2-#, 1) # MAX_PATHS_PER_INVOKE
s2.add_TLV(7, 0x06 #-TLV.U4-#, 1) # MAX_PATHS_PER_INVOKE
return s.tlv2raw(b)
end
end
@@ -133,12 +133,12 @@ class Matter_AttributePathIB : Matter_IM_base
var s = TLV.Matter_TLV_list()
s.add_TLV(0, 0x08 #-TLV.BOOL-#, self.tag_compression)
s.add_TLV(1, 0x07 #-TLV.U8-#, self.node)
s.add_TLV(2, 0x05 #-TLV.U2-#, self.endpoint)
s.add_TLV(2, 0x06 #-TLV.U4-#, self.endpoint)
s.add_TLV(3, 0x06 #-TLV.U4-#, self.cluster)
s.add_TLV(4, 0x06 #-TLV.U4-#, self.attribute)
# Re-emit ListIndex only when it was present, preserving append semantics.
if self.list_index_present
s.add_TLV(5, self.list_index_is_null ? 0x14 #-TLV.NULL-# : 0x05 #-TLV.U2-#, self.list_index)
s.add_TLV(5, self.list_index_is_null ? 0x14 #-TLV.NULL-# : 0x06 #-TLV.U4-#, self.list_index)
end
return s
end
@@ -167,7 +167,7 @@ class Matter_ClusterPathIB : Matter_IM_base
var TLV = matter.TLV
var s = TLV.Matter_TLV_list()
s.add_TLV(0, 0x07 #-TLV.U8-#, self.node)
s.add_TLV(1, 0x05 #-TLV.U2-#, self.endpoint)
s.add_TLV(1, 0x06 #-TLV.U4-#, self.endpoint)
s.add_TLV(2, 0x06 #-TLV.U4-#, self.cluster)
return s
end
@@ -306,7 +306,7 @@ class Matter_EventPathIB : Matter_IM_base
var TLV = matter.TLV
if s == nil s = TLV.Matter_TLV_list() end
s.add_TLV(0, 0x07 #-TLV.U8-#, self.node)
s.add_TLV(1, 0x05 #-TLV.U2-#, self.endpoint)
s.add_TLV(1, 0x06 #-TLV.U4-#, self.endpoint)
s.add_TLV(2, 0x06 #-TLV.U4-#, self.cluster)
s.add_TLV(3, 0x06 #-TLV.U4-#, self.event)
s.add_TLV(4, 0x08 #-TLV.BOOL-#, self.is_urgent)
@@ -352,7 +352,7 @@ class Matter_EventDataIB : Matter_IM_base
self.path.to_TLV(s.add_list(0))
end
s.add_TLV(1, 0x07 #-TLV.U8-#, self.event_number)
s.add_TLV(2, 0x04 #-TLV.U1-#, self.priority)
s.add_TLV(2, 0x06 #-TLV.U4-#, self.priority)
s.add_TLV(3, 0x07 #-TLV.U8-#, self.epoch_timestamp)
s.add_TLV(4, 0x07 #-TLV.U8-#, self.system_timestamp)
s.add_TLV(5, 0x07 #-TLV.U8-#, self.delta_epoch_timestamp)
@@ -409,7 +409,7 @@ class Matter_CommandPathIB : Matter_IM_base
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_list()
s.add_TLV(0, 0x05 #-TLV.U2-#, self.endpoint)
s.add_TLV(0, 0x06 #-TLV.U4-#, self.endpoint)
s.add_TLV(1, 0x06 #-TLV.U4-#, self.cluster)
s.add_TLV(2, 0x06 #-TLV.U4-#, self.command)
return s
@@ -562,8 +562,8 @@ class Matter_StatusIB : Matter_IM_base
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, 0x05 #-TLV.U2-#, self.status)
s.add_TLV(1, 0x05 #-TLV.U2-#, self.cluster_status)
s.add_TLV(0, 0x06 #-TLV.U4-#, self.status)
s.add_TLV(1, 0x06 #-TLV.U4-#, self.cluster_status)
return s
end
end
@@ -602,7 +602,7 @@ class Matter_StatusResponseMessage : Matter_IM_Message_base
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, 0x06 #-TLV.U4-#, self.status)
s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
return s
end
end
@@ -638,7 +638,7 @@ class Matter_ReadRequestMessage : Matter_IM_Message_base
# self.to_TLV_array(s, 2, self.event_filters)
# s.add_TLV(3, 0x08 #-TLV.BOOL-#, self.fabric_filtered)
# self.to_TLV_array(s, 4, self.data_version_filters)
# s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
# s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
# return s
# end
end
@@ -909,7 +909,7 @@ class Matter_ReportDataMessage : Matter_IM_Message_base
self.to_TLV_array(s, 2, self.event_reports)
s.add_TLV(3, 0x08 #-TLV.BOOL-#, self.more_chunked_messages)
s.add_TLV(4, 0x08 #-TLV.BOOL-#, self.suppress_response)
s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
return s
end
end
@@ -947,14 +947,14 @@ class Matter_SubscribeRequestMessage : Matter_IM_Message_base
# var TLV = matter.TLV
# var s = TLV.Matter_TLV_struct()
# s.add_TLV(0, 0x08 #-TLV.BOOL-#, self.keep_subscriptions)
# s.add_TLV(1, 0x05 #-TLV.U2-#, self.min_interval_floor)
# s.add_TLV(2, 0x05 #-TLV.U2-#, self.max_interval_ceiling)
# s.add_TLV(1, 0x06 #-TLV.U4-#, self.min_interval_floor)
# s.add_TLV(2, 0x06 #-TLV.U4-#, self.max_interval_ceiling)
# self.to_TLV_array(s, 3, self.attributes_requests)
# self.to_TLV_array(s, 4, self.event_requests)
# self.to_TLV_array(s, 5, self.event_filters)
# s.add_TLV(7, 0x08 #-TLV.BOOL-#, self.fabric_filtered)
# self.to_TLV_array(s, 8, self.data_version_filters)
# s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
# s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
# return s
# end
end
@@ -980,8 +980,8 @@ class Matter_SubscribeResponseMessage : Matter_IM_Message_base
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, 0x06 #-TLV.U4-#, self.subscription_id)
s.add_TLV(2, 0x05 #-TLV.U2-#, self.max_interval)
s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
s.add_TLV(2, 0x06 #-TLV.U4-#, self.max_interval)
s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
return s
end
end
@@ -1014,7 +1014,7 @@ class Matter_WriteRequestMessage : Matter_IM_Message_base
# s.add_TLV(1, 0x08 #-TLV.BOOL-#, self.timed_request)
# self.to_TLV_array(s, 2, self.write_requests)
# s.add_TLV(3, 0x08 #-TLV.BOOL-#, self.more_chunked_messages)
# s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
# s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
# return s
# end
end
@@ -1038,7 +1038,7 @@ class Matter_WriteResponseMessage : Matter_IM_Message_base
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
self.to_TLV_array(s, 0, self.write_responses)
s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
return s
end
end
@@ -1061,8 +1061,8 @@ class Matter_TimedRequestMessage : Matter_IM_Message_base
# def to_TLV()
# var TLV = matter.TLV
# var s = TLV.Matter_TLV_struct()
# s.add_TLV(0, 0x05 #-TLV.U2-#, self.timeout)
# s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
# s.add_TLV(0, 0x06 #-TLV.U4-#, self.timeout)
# s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
# return s
# end
end
@@ -1092,7 +1092,7 @@ class Matter_InvokeRequestMessage : Matter_IM_Message_base
# s.add_TLV(0, 0x08 #-TLV.BOOL-#, self.suppress_response)
# s.add_TLV(1, 0x08 #-TLV.BOOL-#, self.timed_request)
# self.to_TLV_array(s, 2, self.invoke_requests)
# s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
# s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
# return s
# end
end
@@ -1119,7 +1119,7 @@ class Matter_InvokeResponseMessage : Matter_IM_Message_base
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, 0x08 #-TLV.BOOL-#, self.suppress_response)
self.to_TLV_array(s, 1, self.invoke_responses)
s.add_TLV(0xFF, 0x04 #-TLV.U1-#, self.InteractionModelRevision)
s.add_TLV(0xFF, 0x06 #-TLV.U4-#, self.InteractionModelRevision)
return s
end
end
@@ -426,8 +426,8 @@ matter_device.events.dump()
var types = self.TYPES
for dt: types.keys()
var d1 = dtl.add_struct()
d1.add_TLV(0, 0x05 #-TLV.U2-#, dt) # DeviceType
d1.add_TLV(1, 0x05 #-TLV.U2-#, types[dt]) # Revision
d1.add_TLV(0, 0x06 #-TLV.U4-#, dt) # DeviceType
d1.add_TLV(1, 0x06 #-TLV.U4-#, types[dt]) # Revision
end
return dtl
elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ----------
@@ -460,7 +460,7 @@ matter_device.events.dump()
var attr_list_bytes_sz = (attr_list_bytes != nil) ? size(attr_list_bytes) / 2 : 0
var idx = 0
while idx < attr_list_bytes_sz
acli.add_TLV(nil, 0x05 #-TLV.U2-#, attr_list_bytes.get(idx * 2, -2))
acli.add_TLV(nil, 0x06 #-TLV.U4-#, attr_list_bytes.get(idx * 2, -2))
idx += 1
end
return acli # TODO, empty list for now
@@ -78,16 +78,16 @@ class Matter_Plugin_Aggregator : Matter_Plugin
# ====================================================================================================
if cluster == 0x0003 # ========== Identify 1.2 p.16 ==========
if attribute == 0x0000 # ---------- IdentifyTime / u2 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0) # no identification in progress
return tlv_solo.set(0x06 #-TLV.U4-#, 0) # no identification in progress
elif attribute == 0x0001 # ---------- IdentifyType / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0) # IdentifyType = 0x00 None
return tlv_solo.set(0x06 #-TLV.U4-#, 0) # IdentifyType = 0x00 None
end
elif cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ==========
if attribute == 0x0002 # ---------- ClientList / list[cluster-id] ----------
var pl = TLV.Matter_TLV_array()
# from connectedhome reference implementation
pl.add_TLV(nil, 0x05 #-TLV.U2-#, 0x001E) # Binding
pl.add_TLV(nil, 0x06 #-TLV.U4-#, 0x001E) # Binding
return pl
# overwrite PartsList
elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]----------
@@ -95,7 +95,7 @@ class Matter_Plugin_Aggregator : Matter_Plugin
for plugin: self.device.plugins
var ep = plugin.get_endpoint()
if ep != 0x0001 #-matter.AGGREGATOR_ENDPOINT-# && ep != 0 && plugin.AGGREGATE
pl.add_TLV(nil, 0x05 #-TLV.U2-#, ep) # add each top-level endpoint
pl.add_TLV(nil, 0x06 #-TLV.U4-#, ep) # add each top-level endpoint
end
end
return pl
@@ -126,7 +126,7 @@ class Matter_Plugin_Aggregator : Matter_Plugin
# ID=1
# 0=Certificate (octstr)
var iqr = TLV.Matter_TLV_struct()
iqr.add_TLV(0, 0x05 #-TLV.U2-#, 0) # Timeout
iqr.add_TLV(0, 0x06 #-TLV.U4-#, 0) # Timeout
ctx.command = 0x00 # IdentifyQueryResponse
return iqr
elif command == 0x0040 # ---------- TriggerEffect ----------
@@ -216,15 +216,15 @@ class Matter_Plugin_Device : Matter_Plugin
# ====================================================================================================
if cluster == 0x0003 # ========== Identify 1.2 p.16 ==========
if attribute == 0x0000 # ---------- IdentifyTime / u2 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0) # no identification in progress
return tlv_solo.set(0x06 #-TLV.U4-#, 0) # no identification in progress
elif attribute == 0x0001 # ---------- IdentifyType / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0) # IdentifyType = 0x00 None
return tlv_solo.set(0x06 #-TLV.U4-#, 0) # IdentifyType = 0x00 None
end
# ====================================================================================================
elif cluster == 0x0004 # ========== Groups 1.3 p.21 ==========
if attribute == 0x0000 # ---------- NameSupport ----------
return tlv_solo.set(0x04 #-TLV.U1-#, self.device.GROUP_TRANSPORT_READY ? 0x80 : 0)
return tlv_solo.set(0x06 #-TLV.U4-#, self.device.GROUP_TRANSPORT_READY ? 0x80 : 0)
elif attribute == 0xFFFC # ---------- FeatureMap ----------
return tlv_solo.set(0x06 #-TLV.U4-#, self.device.GROUP_TRANSPORT_READY ? 1 : 0)
end
@@ -242,14 +242,14 @@ class Matter_Plugin_Device : Matter_Plugin
var types = self.TYPES
for dt: types.keys()
var d1 = dtl.add_struct()
d1.add_TLV(0, 0x05 #-TLV.U2-#, dt) # DeviceType
d1.add_TLV(1, 0x05 #-TLV.U2-#, types[dt]) # Revision
d1.add_TLV(0, 0x06 #-TLV.U4-#, dt) # DeviceType
d1.add_TLV(1, 0x06 #-TLV.U4-#, types[dt]) # Revision
end
# if fabric is not Alexa
if (self.NON_BRIDGE_VENDOR.find(session.get_admin_vendor()) == nil) && (!self.device.disable_bridge_mode)
var d1 = dtl.add_struct()
d1.add_TLV(0, 0x05 #-TLV.U2-#, 0x0013) # DeviceType
d1.add_TLV(1, 0x05 #-TLV.U2-#, 1) # Revision
d1.add_TLV(0, 0x06 #-TLV.U4-#, 0x0013) # DeviceType
d1.add_TLV(1, 0x06 #-TLV.U4-#, 1) # Revision
end
return dtl
end
@@ -328,7 +328,7 @@ class Matter_Plugin_Device : Matter_Plugin
# ID=1
# 0=Certificate (octstr)
var iqr = TLV.Matter_TLV_struct()
iqr.add_TLV(0, 0x05 #-TLV.U2-#, 0) # Timeout
iqr.add_TLV(0, 0x06 #-TLV.U4-#, 0) # Timeout
ctx.command = 0x00 # IdentifyQueryResponse
return iqr
elif command == 0x0040 # ---------- TriggerEffect ----------
@@ -365,8 +365,8 @@ class Matter_Plugin_Device : Matter_Plugin
fabric.add_group_endpoint(group_id, self.endpoint, group_name)
end
var response = TLV.Matter_TLV_struct()
response.add_TLV(0, 0x04 #-TLV.U1-#, status)
response.add_TLV(1, 0x05 #-TLV.U2-#, group_id)
response.add_TLV(0, 0x06 #-TLV.U4-#, status)
response.add_TLV(1, 0x06 #-TLV.U4-#, group_id)
ctx.command = 0x0000 # AddGroupResponse
return response
@@ -380,10 +380,10 @@ class Matter_Plugin_Device : Matter_Plugin
var member = self.device.GROUP_TRANSPORT_READY &&
group != nil && group.find("endpoints", []).find(self.endpoint) != nil
var response = TLV.Matter_TLV_struct()
response.add_TLV(0, 0x04 #-TLV.U1-#,
response.add_TLV(0, 0x06 #-TLV.U4-#,
group_id == 0 ? 0x87 #-matter.CONSTRAINT_ERROR-# :
member ? 0 : 0x8B #-matter.NOT_FOUND-#)
response.add_TLV(1, 0x05 #-TLV.U2-#, group_id)
response.add_TLV(1, 0x06 #-TLV.U4-#, group_id)
response.add_TLV(2, 0x0C #-TLV.UTF1-#, member ? group.find("name", "") : "")
ctx.command = 0x0001 # ViewGroupResponse
return response
@@ -391,7 +391,7 @@ class Matter_Plugin_Device : Matter_Plugin
elif command == 0x0002 # ---------- GetGroupMembership ----------
var requested = val.findsub(0)
var response = TLV.Matter_TLV_struct()
response.add_TLV(0, 0x04 #-TLV.U1-#,
response.add_TLV(0, 0x06 #-TLV.U4-#,
self.device.GROUP_TRANSPORT_READY ? 4 - size(fabric.get_group_table()) : 0)
var groups = response.add_array(1)
if self.device.GROUP_TRANSPORT_READY
@@ -409,7 +409,7 @@ class Matter_Plugin_Device : Matter_Plugin
end
end
if include
groups.add_TLV(nil, 0x05 #-TLV.U2-#, group.find("group_id"))
groups.add_TLV(nil, 0x06 #-TLV.U4-#, group.find("group_id"))
end
end
end
@@ -424,10 +424,10 @@ class Matter_Plugin_Device : Matter_Plugin
end
var removed = group_id != 0 && fabric.remove_group_endpoint(group_id, self.endpoint)
var response = TLV.Matter_TLV_struct()
response.add_TLV(0, 0x04 #-TLV.U1-#,
response.add_TLV(0, 0x06 #-TLV.U4-#,
group_id == 0 ? 0x87 #-matter.CONSTRAINT_ERROR-# :
removed ? 0 : 0x8B #-matter.NOT_FOUND-#)
response.add_TLV(1, 0x05 #-TLV.U2-#, group_id)
response.add_TLV(1, 0x06 #-TLV.U4-#, group_id)
ctx.command = 0x0003 # RemoveGroupResponse
return response
@@ -641,7 +641,7 @@ class Matter_Plugin_Root : Matter_Plugin
super(self).init(device, endpoint, config)
# publish mandatory events
self.publish_event(0x0028, 0x00, 2 #-matter.EVENT_CRITICAL-#, matter.TLV.Matter_TLV_item().set(0x06 #-matter.TLV.U4-#, tasmota.version())) # Event StartUp - Software Version
self.publish_event(0x0033, 0x03, 2 #-matter.EVENT_CRITICAL-#, matter.TLV.Matter_TLV_item().set(0x04 #-matter.TLV.U1-#, 1)) # Event BootReason - PowerOnReboot - TODO if we need to refine
self.publish_event(0x0033, 0x03, 2 #-matter.EVENT_CRITICAL-#, matter.TLV.Matter_TLV_item().set(0x06 #-matter.TLV.U4-#, 1)) # Event BootReason - PowerOnReboot - TODO if we need to refine
end
# Open or resume the GroupKeyMap list-write transaction for this exchange.
@@ -689,11 +689,11 @@ class Matter_Plugin_Root : Matter_Plugin
var result = TLV.Matter_TLV_array()
if fabric != nil
var out = result.add_struct(nil)
out.add_TLV(1, 0x04 #-TLV.U1-#, 5) # Administer
out.add_TLV(2, 0x04 #-TLV.U1-#, 2) # CASE
out.add_TLV(1, 0x06 #-TLV.U4-#, 5) # Administer
out.add_TLV(2, 0x06 #-TLV.U4-#, 2) # CASE
out.add_TLV(3, 0x14 #-TLV.NULL-#, nil) # all CASE subjects
out.add_TLV(4, 0x14 #-TLV.NULL-#, nil) # all targets
out.add_TLV(0xFE, 0x04 #-TLV.U1-#, fabric.get_fabric_index())
out.add_TLV(0xFE, 0x06 #-TLV.U4-#, fabric.get_fabric_index())
end
return result
end
@@ -709,9 +709,9 @@ class Matter_Plugin_Root : Matter_Plugin
end
for entry : fabric.get_group_key_map()
var out = result.add_struct(nil)
out.add_TLV(1, 0x05 #-TLV.U2-#, entry.find("group_id"))
out.add_TLV(2, 0x05 #-TLV.U2-#, entry.find("key_set_id"))
out.add_TLV(0xFE, 0x04 #-TLV.U1-#, fabric.get_fabric_index())
out.add_TLV(1, 0x06 #-TLV.U4-#, entry.find("group_id"))
out.add_TLV(2, 0x06 #-TLV.U4-#, entry.find("key_set_id"))
out.add_TLV(0xFE, 0x06 #-TLV.U4-#, fabric.get_fabric_index())
end
return result
end
@@ -825,13 +825,13 @@ class Matter_Plugin_Root : Matter_Plugin
end
for entry : fabric.get_group_table()
var out = result.add_struct(nil)
out.add_TLV(1, 0x05 #-TLV.U2-#, entry.find("group_id"))
out.add_TLV(1, 0x06 #-TLV.U4-#, entry.find("group_id"))
var endpoints = out.add_array(2)
for endpoint : entry.find("endpoints", [])
endpoints.add_TLV(nil, 0x05 #-TLV.U2-#, endpoint)
endpoints.add_TLV(nil, 0x06 #-TLV.U4-#, endpoint)
end
out.add_TLV(3, 0x0C #-TLV.UTF1-#, entry.find("name", ""))
out.add_TLV(0xFE, 0x04 #-TLV.U1-#, fabric.get_fabric_index())
out.add_TLV(0xFE, 0x06 #-TLV.U4-#, fabric.get_fabric_index())
end
return result
end
@@ -902,8 +902,8 @@ class Matter_Plugin_Root : Matter_Plugin
def group_key_set_to_tlv(key_set, id)
var TLV = matter.TLV
var out = TLV.Matter_TLV_struct()
out.add_TLV(0, 0x05 #-TLV.U2-#, id)
out.add_TLV(1, 0x04 #-TLV.U1-#, key_set != nil ? key_set.find("policy", 0) : 0)
out.add_TLV(0, 0x06 #-TLV.U4-#, id)
out.add_TLV(1, 0x06 #-TLV.U4-#, key_set != nil ? key_set.find("policy", 0) : 0)
# KeySetRead never discloses group key material; only epoch start times are returned.
var idx = 0
while idx < 3
@@ -930,13 +930,13 @@ class Matter_Plugin_Root : Matter_Plugin
return tlv_solo.set(0x07 #-TLV.U8-#, session._breadcrumb)
elif attribute == 0x0001 # ---------- BasicCommissioningInfo / BasicCommissioningInfo----------
var bci = TLV.Matter_TLV_struct()
bci.add_TLV(0, 0x05 #-TLV.U2-#, 60) # FailSafeExpiryLengthSeconds
bci.add_TLV(1, 0x05 #-TLV.U2-#, 900) # MaxCumulativeFailsafeSeconds
bci.add_TLV(0, 0x06 #-TLV.U4-#, 60) # FailSafeExpiryLengthSeconds
bci.add_TLV(1, 0x06 #-TLV.U4-#, 900) # MaxCumulativeFailsafeSeconds
return bci
elif attribute == 0x0002 # ---------- RegulatoryConfig / RegulatoryLocationType ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 2) # 2 = IndoorOutdoor | esp-matter = 0
return tlv_solo.set(0x06 #-TLV.U4-#, 2) # 2 = IndoorOutdoor | esp-matter = 0
elif attribute == 0x0003 # ---------- LocationCapability / RegulatoryLocationType----------
return tlv_solo.set(0x04 #-TLV.U1-#, 2) # 2 = IndoorOutdoor
return tlv_solo.set(0x06 #-TLV.U4-#, 2) # 2 = IndoorOutdoor
elif attribute == 0x0004 # ---------- SupportsConcurrentConnection / bool ----------
return tlv_solo.set(0x08 #-TLV.BOOL-#, false) # false - maybe can set to true
end
@@ -964,7 +964,7 @@ class Matter_Plugin_Root : Matter_Plugin
var ip6 = eth.add_array(6) # IPv6Addresses
ip6.add_TLV(nil, 0x10 #-TLV.B1-#, matter.get_ip_bytes(tas_eth.find("ip6local", "")))
ip6.add_TLV(nil, 0x10 #-TLV.B1-#, matter.get_ip_bytes(tas_eth.find("ip6", "")))
eth.add_TLV(7, 0x04 #-TLV.U1-#, 2) # InterfaceType, p646
eth.add_TLV(7, 0x06 #-TLV.U4-#, 2) # InterfaceType, p646
end
var tas_wif = tasmota.wifi()
@@ -981,11 +981,11 @@ class Matter_Plugin_Root : Matter_Plugin
var ip6 = wif.add_array(6) # IPv6Addresses
ip6.add_TLV(nil, 0x10 #-TLV.B1-#, matter.get_ip_bytes(tas_wif.find("ip6local", "")))
ip6.add_TLV(nil, 0x10 #-TLV.B1-#, matter.get_ip_bytes(tas_wif.find("ip6", "")))
wif.add_TLV(7, 0x04 #-TLV.U1-#, 1) # InterfaceType, p646
wif.add_TLV(7, 0x06 #-TLV.U4-#, 1) # InterfaceType, p646
end
return nwi
elif attribute == 0x0001 # ---------- RebootCount u16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, tasmota.cmd("Status 1", true)['StatusPRM']['BootCount'])
return tlv_solo.set(0x06 #-TLV.U4-#, tasmota.cmd("Status 1", true)['StatusPRM']['BootCount'])
elif attribute == 0x0002 # ---------- UpTime u16 ----------
return tlv_solo.set(0x06 #-TLV.U4-#, tasmota.cmd("Status 11", true)['StatusSTS']['UptimeSec'])
# TODO add later other attributes
@@ -1008,7 +1008,7 @@ class Matter_Plugin_Root : Matter_Plugin
var epoch_us = (int64(unix_time) - int64(946684800 #-self.MATTER_EPOCH_OFFSET-#)) * int64(1000000)
return tlv_solo.set(0x07 #-TLV.U8-#, epoch_us)
elif attribute == 0x0001 # ---------- Granularity / enum ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 3) # MillisecondsGranularity (NTP every hour, i.e. 36ms max drift)
return tlv_solo.set(0x06 #-TLV.U4-#, 3) # MillisecondsGranularity (NTP every hour, i.e. 36ms max drift)
# TODO add some missing args
elif attribute == 0x0007 # ---------- LocalTime / epoch_us ----------
var unix_time = tasmota.rtc('local')
@@ -1033,7 +1033,7 @@ class Matter_Plugin_Root : Matter_Plugin
var nocs = nocl.add_struct(nil)
nocs.add_TLV(1, 0x11 #-TLV.B2-#, loc_fabric.get_noc()) # NOC
nocs.add_TLV(2, 0x11 #-TLV.B2-#, loc_fabric.get_icac()) # ICAC
nocs.add_TLV(0xFE, 0x05 #-TLV.U2-#, loc_fabric.get_fabric_index()) # Label
nocs.add_TLV(0xFE, 0x06 #-TLV.U4-#, loc_fabric.get_fabric_index()) # Label
end
return nocl
elif attribute == 0x0001 # ---------- Fabrics / list[FabricDescriptorStruct] ----------
@@ -1045,24 +1045,24 @@ class Matter_Plugin_Root : Matter_Plugin
var root_ca_tlv = TLV.parse(loc_fabric.get_ca())
var fab = fabrics.add_struct(nil) # encoding see p.303
fab.add_TLV(1, 0x11 #-TLV.B2-#, root_ca_tlv.findsubval(9)) # RootPublicKey
fab.add_TLV(2, 0x05 #-TLV.U2-#, loc_fabric.get_admin_vendor()) # VendorID
fab.add_TLV(2, 0x06 #-TLV.U4-#, loc_fabric.get_admin_vendor()) # VendorID
fab.add_TLV(3, 0x07 #-TLV.U8-#, loc_fabric.get_fabric_id_as_int64()) # FabricID
fab.add_TLV(4, 0x07 #-TLV.U8-#, loc_fabric.get_device_id_as_int64()) # NodeID
fab.add_TLV(5, 0x0C #-TLV.UTF1-#, loc_fabric.get_fabric_label()) # Label
fab.add_TLV(0xFE, 0x05 #-TLV.U2-#, loc_fabric.get_fabric_index()) # idx
fab.add_TLV(0xFE, 0x06 #-TLV.U4-#, loc_fabric.get_fabric_index()) # idx
end
return fabrics
elif attribute == 0x0002 # ---------- SupportedFabrics / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, matter.Fabric._MAX_CASE) # Max 5 fabrics
return tlv_solo.set(0x06 #-TLV.U4-#, matter.Fabric._MAX_CASE) # Max 5 fabrics
elif attribute == 0x0003 # ---------- CommissionedFabrics / u1 ----------
var fabric_actice = self.device.sessions.count_active_fabrics()
return tlv_solo.set(0x04 #-TLV.U1-#, fabric_actice) # number of active fabrics
return tlv_solo.set(0x06 #-TLV.U4-#, fabric_actice) # number of active fabrics
elif attribute == 0x0004 # ---------- TrustedRootCertificates / list[octstr] ----------
# TODO
elif attribute == 0x0005 # ---------- Current FabricIndex / u1 ----------
var fab_index = session._fabric.get_fabric_index()
if fab_index == nil fab_index = 0 end # if PASE session, then the fabric index should be zero
return tlv_solo.set(0x04 #-TLV.U1-#, fab_index) # number of active sessions
return tlv_solo.set(0x06 #-TLV.U4-#, fab_index) # number of active sessions
end
# ====================================================================================================
@@ -1071,16 +1071,16 @@ class Matter_Plugin_Root : Matter_Plugin
var commissioning_open = self.device.commissioning.is_commissioning_open()
var basic_commissioning = self.device.commissioning.is_root_commissioning_open()
var val = commissioning_open ? (basic_commissioning ? 2 #-BasicWindowOpen-# : 1 #-EnhancedWindowOpen-#) : 0 #-WindowNotOpen-#
return tlv_solo.set(0x04 #-TLV.U1-#, val)
return tlv_solo.set(0x06 #-TLV.U4-#, val)
elif attribute == 0x0001 # ---------- AdminFabricIndex / u16 ----------
var admin_fabric = self.device.commissioning.commissioning_admin_fabric
if admin_fabric != nil
return tlv_solo.set_or_nil(0x05 #-TLV.U2-#, admin_fabric.get_fabric_index())
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, admin_fabric.get_fabric_index())
end
elif attribute == 0x0002 # ---------- AdminVendorId / u16 ----------
var admin_fabric = self.device.commissioning.commissioning_admin_fabric
if admin_fabric != nil
return tlv_solo.set_or_nil(0x05 #-TLV.U2-#, admin_fabric.get_admin_vendor())
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, admin_fabric.get_admin_vendor())
end
end
@@ -1089,21 +1089,21 @@ class Matter_Plugin_Root : Matter_Plugin
self.ack_request(ctx) # long operation, send Ack first
if attribute == 0x0000 # ---------- DataModelRevision ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 21) # Matter 1.6.1 data model
return tlv_solo.set(0x06 #-TLV.U4-#, 21) # Matter 1.6.1 data model
elif attribute == 0x0001 # ---------- VendorName / string ----------
return tlv_solo.set(0x0C #-TLV.UTF1-#, "Tasmota")
elif attribute == 0x0002 # ---------- VendorID / vendor-id ----------
return tlv_solo.set(0x05 #-TLV.U2-#, self.device.VENDOR_ID) # Vendor ID reserved for development
return tlv_solo.set(0x06 #-TLV.U4-#, self.device.VENDOR_ID) # Vendor ID reserved for development
elif attribute == 0x0003 # ---------- ProductName / string ----------
return tlv_solo.set(0x0C #-TLV.UTF1-#, tasmota.cmd("DeviceName", true)['DeviceName'])
elif attribute == 0x0004 # ---------- ProductID / u16 (opt) ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 32768) # taken from esp-matter example
return tlv_solo.set(0x06 #-TLV.U4-#, 32768) # taken from esp-matter example
elif attribute == 0x0005 # ---------- NodeLabel / string ----------
return tlv_solo.set(0x0C #-TLV.UTF1-#, tasmota.cmd("FriendlyName", true)['FriendlyName1'])
elif attribute == 0x0006 # ---------- Location / string ----------
return tlv_solo.set(0x0C #-TLV.UTF1-#, "XX") # no location
elif attribute == 0x0007 # ---------- HardwareVersion / u16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0x0008 # ---------- HardwareVersionString / string ----------
return tlv_solo.set(0x0C #-TLV.UTF1-#, tasmota.cmd("Status 2", true)['StatusFWR']['Hardware'])
elif attribute == 0x0009 # ---------- SoftwareVersion / u32 ----------
@@ -1121,17 +1121,17 @@ class Matter_Plugin_Root : Matter_Plugin
return tlv_solo.set(0x0C #-TLV.UTF1-#, tasmota.wifi().find("mac", ""))
elif attribute == 0x0013 # ---------- CapabilityMinima / CapabilityMinimaStruct ----------
var cps = TLV.Matter_TLV_struct()
cps.add_TLV(0, 0x05 #-TLV.U2-#, 3) # CaseSessionsPerFabric = 3
cps.add_TLV(1, 0x05 #-TLV.U2-#, 3) # SubscriptionsPerFabric = 3
cps.add_TLV(2, 0x05 #-TLV.U2-#, 1) # SimultaneousInvocationsSupported
cps.add_TLV(3, 0x05 #-TLV.U2-#, 1) # SimultaneousWritesSupported
cps.add_TLV(4, 0x05 #-TLV.U2-#, 9) # ReadPathsSupported
cps.add_TLV(5, 0x05 #-TLV.U2-#, 3) # SubscribePathsSupported
cps.add_TLV(0, 0x06 #-TLV.U4-#, 3) # CaseSessionsPerFabric = 3
cps.add_TLV(1, 0x06 #-TLV.U4-#, 3) # SubscriptionsPerFabric = 3
cps.add_TLV(2, 0x06 #-TLV.U4-#, 1) # SimultaneousInvocationsSupported
cps.add_TLV(3, 0x06 #-TLV.U4-#, 1) # SimultaneousWritesSupported
cps.add_TLV(4, 0x06 #-TLV.U4-#, 9) # ReadPathsSupported
cps.add_TLV(5, 0x06 #-TLV.U4-#, 3) # SubscribePathsSupported
return cps
elif attribute == 0x0015 # ---------- SpecificationVersion / uint32 ----------
return tlv_solo.set(0x06 #-TLV.U4-#, 0x01060100) # Matter 1.6.1.0
elif attribute == 0x0016 # ---------- MaxPathsPerInvoke / uint16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 1)
return tlv_solo.set(0x06 #-TLV.U4-#, 1)
elif attribute == 0x0018 # ---------- ConfigurationVersion / uint32 ----------
return tlv_solo.set(0x06 #-TLV.U4-#, self.device.configuration_version)
end
@@ -1142,11 +1142,11 @@ class Matter_Plugin_Root : Matter_Plugin
if attribute == 0x0000 # ---------- ACL / list[AccessControlEntryStruct] ----------
return self.fixed_acl_to_tlv(session.get_fabric())
elif attribute == 0x0002 # ---------- SubjectsPerAccessControlEntry / uint16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 4) # spec minimum
return tlv_solo.set(0x06 #-TLV.U4-#, 4) # spec minimum
elif attribute == 0x0003 # ---------- TargetsPerAccessControlEntry / uint16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 3) # spec minimum
return tlv_solo.set(0x06 #-TLV.U4-#, 3) # spec minimum
elif attribute == 0x0004 # ---------- AccessControlEntriesPerFabric / uint16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 1) # one fixed wildcard entry
return tlv_solo.set(0x06 #-TLV.U4-#, 1) # one fixed wildcard entry
end
# ====================================================================================================
@@ -1161,9 +1161,9 @@ class Matter_Plugin_Root : Matter_Plugin
elif attribute == 0x0002 # ---------- MaxGroupsPerFabric / uint16 ----------
# Groups remains discoverable for unicast compatibility, but group
# provisioning is fail-closed until encrypted multicast receive exists.
return tlv_solo.set(0x05 #-TLV.U2-#, self.device.GROUP_TRANSPORT_READY ? 4 : 0)
return tlv_solo.set(0x06 #-TLV.U4-#, self.device.GROUP_TRANSPORT_READY ? 4 : 0)
elif attribute == 0x0003 # ---------- MaxGroupKeysPerFabric / uint16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 3) # spec minimum
return tlv_solo.set(0x06 #-TLV.U4-#, 3) # spec minimum
elif attribute == 0xFFF8 # ---------- GeneratedCommandList ----------
var generated = TLV.Matter_TLV_array()
generated.add_TLV(nil, 0x06 #-TLV.U4-#, 0x0002) # KeySetReadResponse
@@ -1186,7 +1186,7 @@ class Matter_Plugin_Root : Matter_Plugin
elif attribute == 0x0001 # ---------- UpdatePossible / bool ----------
return tlv_solo.set(0x08 #-TLV.BOOL-#, 0) # we claim that update is not possible, would require to go to Tasmota UI
elif attribute == 0x0002 # ---------- UpdateState / UpdateStateEnum ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 1) # Idle
return tlv_solo.set(0x06 #-TLV.U4-#, 1) # Idle
elif attribute == 0x0003 # ---------- UpdateStateProgress / uint8 ----------
return tlv_solo.set(0x14 #-TLV.NULL-#, nil) # null, nothing in process
end
@@ -1206,12 +1206,12 @@ class Matter_Plugin_Root : Matter_Plugin
elif cluster == 0x002C # ========== Time Format Localization Cluster 11.4 p.581 ==========
if attribute == 0x0000 # ---------- HourFormat / HourFormat ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 1) # 1 = 24hr
return tlv_solo.set(0x06 #-TLV.U4-#, 1) # 1 = 24hr
elif attribute == 0x0001 # ---------- ActiveCalendarType / CalendarType ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 4) # 4 = Gregorian
return tlv_solo.set(0x06 #-TLV.U4-#, 4) # 4 = Gregorian
elif attribute == 0x0002 # ---------- SupportedCalendarTypes / list[CalendarType] ----------
var callist = TLV.Matter_TLV_array()
callist.add_TLV(nil, TLV.create_TLV(0x04 #-TLV.U1-#, 4))
callist.add_TLV(nil, 0x06 #-TLV.U4-#, 4) # 4 = Gregorian
return callist
end
@@ -1221,13 +1221,13 @@ class Matter_Plugin_Root : Matter_Plugin
if attribute == 0x0000 # ---------- TemperatureUnit / TempUnitEnum ----------
# 0=Fahrenheit, 1=Celsius, 2=Kelvin
# SetOption8: 0=Celsius, 1=Fahrenheit -> Matter: 0=Fahrenheit, 1=Celsius (inverted)
return tlv_solo.set(0x04 #-TLV.U1-#, tasmota.get_option(8) ? 0 : 1)
return tlv_solo.set(0x06 #-TLV.U4-#, tasmota.get_option(8) ? 0 : 1)
end
# ====================================================================================================
elif cluster == 0x0031 # ========== Network Commissioning Cluster cluster 11.8 p.606 ==========
if attribute == 0x0003 # ---------- ConnectMaxTimeSeconds / uint8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 30) # 30 - value taking from example in esp-matter
return tlv_solo.set(0x06 #-TLV.U4-#, 30) # 30 - value taking from example in esp-matter
end
elif cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ==========
@@ -1236,7 +1236,7 @@ class Matter_Plugin_Root : Matter_Plugin
if attribute == 0x0002 # ---------- ClientList / list[cluster-id] ----------
var pl = TLV.Matter_TLV_array()
# from connectedhome reference implementation
pl.add_TLV(nil, 0x05 #-TLV.U2-#, 0x001F) # Access Control Cluster
pl.add_TLV(nil, 0x06 #-TLV.U4-#, 0x001F) # Access Control Cluster
return pl
# overwrite PartsList
elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]----------
@@ -1246,7 +1246,7 @@ class Matter_Plugin_Root : Matter_Plugin
for ep: eps
# if bridge mode is disabled, don't announce Aggregatore (above 0xFF00)
if !disable_bridge_mode || ep != 0x0001 #-matter.AGGREGATOR_ENDPOINT-#
pl.add_TLV(nil, 0x05 #-TLV.U2-#, ep) # add each endpoint
pl.add_TLV(nil, 0x06 #-TLV.U4-#, ep) # add each endpoint
end
end
return pl
@@ -1270,7 +1270,7 @@ class Matter_Plugin_Root : Matter_Plugin
return tlv_solo.set(0x06 #-TLV.U4-#, 300)
elif attribute == 0x0002 # ---------- ActiveModeThreshold / uint16 (milliseconds) ----------
# For always-on WiFi device: 300ms (spec default)
return tlv_solo.set(0x05 #-TLV.U2-#, 300)
return tlv_solo.set(0x06 #-TLV.U4-#, 300)
# Note: attributes 0x0003-0x0005 require CIP feature (Check-In Protocol)
# Note: attribute 0x0008 (OperatingMode) requires LITS feature (Long Idle Time Support)
# We don't implement CIP or LITS since this is an always-on WiFi device
@@ -1302,7 +1302,7 @@ class Matter_Plugin_Root : Matter_Plugin
session._breadcrumb = Breadcrumb
var afsr = TLV.Matter_TLV_struct()
afsr.add_TLV(0, 0x04 #-TLV.U1-#, 0) # ErrorCode = OK
afsr.add_TLV(0, 0x06 #-TLV.U4-#, 0) # ErrorCode = OK
afsr.add_TLV(1, 0x0C #-TLV.UTF1-#, "") # DebugText = ""
ctx.command = 0x01 # ArmFailSafeResponse
return afsr
@@ -1317,7 +1317,7 @@ class Matter_Plugin_Root : Matter_Plugin
# 0=ErrorCode (OK=0)
# 1=DebugText
var srcr = TLV.Matter_TLV_struct()
srcr.add_TLV(0, 0x04 #-TLV.U1-#, 0) # ErrorCode = OK
srcr.add_TLV(0, 0x06 #-TLV.U4-#, 0) # ErrorCode = OK
srcr.add_TLV(1, 0x0C #-TLV.UTF1-#, "") # DebugText = ""
ctx.command = 0x03 # SetRegulatoryConfigResponse
return srcr
@@ -1336,7 +1336,7 @@ class Matter_Plugin_Root : Matter_Plugin
# 0=ErrorCode (OK=0)
# 1=DebugText
var ccr = TLV.Matter_TLV_struct()
ccr.add_TLV(0, 0x04 #-TLV.U1-#, 0) # ErrorCode = OK
ccr.add_TLV(0, 0x06 #-TLV.U4-#, 0) # ErrorCode = OK
ccr.add_TLV(1, 0x0C #-TLV.UTF1-#, "") # DebugText = ""
ctx.command = 0x05 # CommissioningCompleteResponse
@@ -1505,8 +1505,8 @@ class Matter_Plugin_Root : Matter_Plugin
# 1=FabricIndex (1-254) (opt)
# 2=DebugText (opt)
var nocr = TLV.Matter_TLV_struct()
nocr.add_TLV(0, 0x04 #-TLV.U1-#, 0x00 #-matter.SUCCESS-#) # Status
nocr.add_TLV(1, 0x04 #-TLV.U1-#, new_fabric.get_fabric_index()) # fabric-index
nocr.add_TLV(0, 0x06 #-TLV.U4-#, 0x00 #-matter.SUCCESS-#) # Status
nocr.add_TLV(1, 0x06 #-TLV.U4-#, new_fabric.get_fabric_index()) # fabric-index
ctx.command = 0x08 # NOCResponse
return nocr
@@ -1520,8 +1520,8 @@ class Matter_Plugin_Root : Matter_Plugin
# 1=FabricIndex (1-254) (opt)
# 2=DebugText (opt)
var nocr = TLV.Matter_TLV_struct()
nocr.add_TLV(0, 0x04 #-TLV.U1-#, 0x00 #-matter.SUCCESS-#) # Status
nocr.add_TLV(1, 0x04 #-TLV.U1-#, session.get_fabric().get_fabric_index()) # fabric-index
nocr.add_TLV(0, 0x06 #-TLV.U4-#, 0x00 #-matter.SUCCESS-#) # Status
nocr.add_TLV(1, 0x06 #-TLV.U4-#, session.get_fabric().get_fabric_index()) # fabric-index
ctx.command = 0x08 # NOCResponse
return nocr
@@ -1541,8 +1541,8 @@ class Matter_Plugin_Root : Matter_Plugin
# 1=FabricIndex (1-254) (opt)
# 2=DebugText (opt)
var nocr = TLV.Matter_TLV_struct()
nocr.add_TLV(0, 0x04 #-TLV.U1-#, 0x00 #-matter.SUCCESS-#) # Status
nocr.add_TLV(1, 0x04 #-TLV.U1-#, index) # fabric-index
nocr.add_TLV(0, 0x06 #-TLV.U4-#, 0x00 #-matter.SUCCESS-#) # Status
nocr.add_TLV(1, 0x06 #-TLV.U4-#, index) # fabric-index
ctx.command = 0x08 # NOCResponse
return nocr
end
@@ -1660,9 +1660,9 @@ class Matter_Plugin_Root : Matter_Plugin
elif command == 0x0004 # ---------- KeySetReadAllIndices ----------
var response = TLV.Matter_TLV_struct()
var indices = response.add_array(0)
indices.add_TLV(nil, 0x05 #-TLV.U2-#, 0) # operational IPK key set
indices.add_TLV(nil, 0x06 #-TLV.U4-#, 0) # operational IPK key set
for key_set : fabric.get_group_key_sets()
indices.add_TLV(nil, 0x05 #-TLV.U2-#, key_set.find("id"))
indices.add_TLV(nil, 0x06 #-TLV.U4-#, key_set.find("id"))
end
ctx.command = 0x0005 # KeySetReadAllIndicesResponse
return response
@@ -1685,9 +1685,9 @@ class Matter_Plugin_Root : Matter_Plugin
tasmota.delay(1000)
var ncresp = TLV.Matter_TLV_struct()
ncresp.add_TLV(0, 0x04 #-TLV.U1-#, 0x00 #-matter.SUCCESS-#) # NetworkCommissioningStatusEnum
ncresp.add_TLV(0, 0x06 #-TLV.U4-#, 0x00 #-matter.SUCCESS-#) # NetworkCommissioningStatusEnum
ncresp.add_TLV(1, 0x0D #-TLV.UTF2-#, tasmota.wifi().tostring()) # DebugText
ncresp.add_TLV(2, 0x04 #-TLV.U1-#, 1) # NetworkIndex
ncresp.add_TLV(2, 0x06 #-TLV.U4-#, 1) # NetworkIndex
ctx.command = 0x05 # NetworkConfigResponse
return ncresp
@@ -230,13 +230,13 @@ class Matter_Plugin_Fan : Matter_Plugin_Device
if cluster == 0x0202 # ========== Fan ==========
self.update_shadow_lazy()
if attribute == 0x0000 # ---------- FanMode / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, self.shadow_fan_mode)
return tlv_solo.set(0x06 #-TLV.U4-#, self.shadow_fan_mode)
elif attribute == 0x0001 # ---------- FanModeSequence / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 2) # Off/Low/Med/High/Auto
return tlv_solo.set(0x06 #-TLV.U4-#, 2) # Off/Low/Med/High/Auto
elif attribute == 0x0002 # ---------- PercentSetting / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, self.shadow_fan_speed_pct)
return tlv_solo.set(0x06 #-TLV.U4-#, self.shadow_fan_speed_pct)
elif attribute == 0x0003 # ---------- PercentSetting / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, self.shadow_fan_speed_pct)
return tlv_solo.set(0x06 #-TLV.U4-#, self.shadow_fan_speed_pct)
end
end
@@ -220,9 +220,9 @@ class Matter_Plugin_Light0 : Matter_Plugin_Device
elif attribute == 0x4000 # ---------- GlobalSceneControl / bool ----------
return tlv_solo.set(0x08 #-TLV.BOOL-#, true)
elif attribute == 0x4001 # ---------- OnTime / u2 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0x4002 # ---------- OffWaitTime / u2 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0x4003 # ---------- StartUpOnOff / enum8 nullable ----------
return tlv_solo.set(0x14 #-TLV.NULL-#, nil)
end
@@ -393,9 +393,9 @@ class Matter_Plugin_Sensor_Air_Quality : Matter_Plugin_Device
elif attribute == 0x0002 # ---------- MaxMeasured Value / float ----------
return tlv_solo.set(0x14 #-TLV.NULL-#, nil)
elif attribute == 0x0008 # ---------- MeasurementUnit / u8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, unit)
return tlv_solo.set(0x06 #-TLV.U4-#, unit)
elif attribute == 0x0009 # ---------- MeasurementMedium / u8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0) # 0 = Air
return tlv_solo.set(0x06 #-TLV.U4-#, 0) # 0 = Air
elif attribute == 0xFFFC # ---------- FeatureMap / map32 ----------
return tlv_solo.set(0x06 #-TLV.U4-#, 1) # MEA = NumericMeasurement
end
@@ -405,7 +405,7 @@ class Matter_Plugin_Sensor_Air_Quality : Matter_Plugin_Device
# ====================================================================================================
if cluster == 0x005B # ========== Air Quality ==========
if attribute == 0x0000 # ---------- AirQuality / U8 ----------
return tlv_solo.set_or_nil(0x04 #-TLV.U1-#, self.shadow_air_quality)
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, self.shadow_air_quality)
# elif attribute == 0xFFFC # ---------- FeatureMap / map32 ----------
# return tlv_solo.set(0x06 #-TLV.U4-#, 0) #
end
@@ -171,11 +171,11 @@ class Matter_Plugin_Sensor_GenericSwitch_Btn : Matter_Plugin_Device
if cluster == 0x003B # ========== Generic Switch, 1.12 ==========
# self.update_shadow_lazy()
if attribute == 0x0000 # ---------- NumberOfPositions / uint8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 2) # default to 2 positions
return tlv_solo.set(0x06 #-TLV.U4-#, 2) # default to 2 positions
elif attribute == 0x0001 # ---------- CurrentPosition / uint8 ----------
return tlv_solo.set_or_nil(0x04 #-TLV.U1-#, self.shadow_position)
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, self.shadow_position)
elif attribute == 0x0002 # ---------- MultiPressMax / uint8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 5) # up to penta press
return tlv_solo.set(0x06 #-TLV.U4-#, 5) # up to penta press
elif attribute == 0xFFFC # ---------- FeatureMap / map32 ----------
return tlv_solo.set(0x06 #-TLV.U4-#, 0x16 #-0x02 | 0x04 | 0x10-#) # MomentarySwitch + MomentarySwitchRelease + MomentarySwitchMultiPress
@@ -214,19 +214,19 @@ class Matter_Plugin_Sensor_GenericSwitch_Btn : Matter_Plugin_Device
# publish event for (mode==1), InitialPress and ShortRelease
if (mode == 1)
if state # InitialPress
self.publish_event(0x003B, 0x01, 1 #-matter.EVENT_INFO-#, matter.TLV.Matter_TLV_item().set(0x04 #-matter.TLV.U1-#, 1)) # InitialPress, position hardcoded to 1
self.publish_event(0x003B, 0x01, 1 #-matter.EVENT_INFO-#, matter.TLV.Matter_TLV_item().set(0x06 #-matter.TLV.U4-#, 1)) # InitialPress, position hardcoded to 1
else
self.publish_event(0x003B, 0x03, 1 #-matter.EVENT_INFO-#, matter.TLV.Matter_TLV_item().set(0x04 #-matter.TLV.U1-#, 1)) # ShortRelease, previous position hardcoded to 1
self.publish_event(0x003B, 0x03, 1 #-matter.EVENT_INFO-#, matter.TLV.Matter_TLV_item().set(0x06 #-matter.TLV.U4-#, 1)) # ShortRelease, previous position hardcoded to 1
end
# check if there is an ungoing multi-press
if (state == 1) && (press_counter > 0)
# MultiPressOngoing
self.publish_event(0x003B, 0x05, 1 #-matter.EVENT_INFO-#, matter.TLV.Matter_TLV_item().set(0x04 #-matter.TLV.U1-#, 1),
matter.TLV.Matter_TLV_item().set(0x04 #-matter.TLV.U1-#, press_counter + 1)) # MultiPressCom­ plete
self.publish_event(0x003B, 0x05, 1 #-matter.EVENT_INFO-#, matter.TLV.Matter_TLV_item().set(0x06 #-matter.TLV.U4-#, 1),
matter.TLV.Matter_TLV_item().set(0x06 #-matter.TLV.U4-#, press_counter + 1)) # MultiPressCom­ plete
end
elif (mode == 2) && (press_counter > 0) # Multipress
self.publish_event(0x003B, 0x06, 1 #-matter.EVENT_INFO-#, matter.TLV.Matter_TLV_item().set(0x04 #-matter.TLV.U1-#, 1),
matter.TLV.Matter_TLV_item().set(0x04 #-matter.TLV.U1-#, press_counter)) # MultiPressCom­ plete
self.publish_event(0x003B, 0x06, 1 #-matter.EVENT_INFO-#, matter.TLV.Matter_TLV_item().set(0x06 #-matter.TLV.U4-#, 1),
matter.TLV.Matter_TLV_item().set(0x06 #-matter.TLV.U4-#, press_counter)) # MultiPressCom­ plete
end
end
@@ -221,13 +221,13 @@ class Matter_Plugin_Shutter : Matter_Plugin_Device
self.update_shadow_lazy()
self.update_inverted()
if attribute == 0x0000 # ---------- Type / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0xFF) # 0xFF = unknown type of shutter
return tlv_solo.set(0x06 #-TLV.U4-#, 0xFF) # 0xFF = unknown type of shutter
elif attribute == 0x0005 # ---------- NumberOfActuationsLift / u16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0x0007 # ---------- ConfigStatus / u8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 1 + 8) # Operational + Lift Position Aware
return tlv_solo.set(0x06 #-TLV.U4-#, 1 + 8) # Operational + Lift Position Aware
elif attribute == 0x000D # ---------- EndProductType / u8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0xFF) # 0xFF = unknown type of shutter
return tlv_solo.set(0x06 #-TLV.U4-#, 0xFF) # 0xFF = unknown type of shutter
elif attribute == 0x000E # ---------- CurrentPositionLiftPercent100ths / u16 ----------
if self.shadow_shutter_pos != nil
if self.shadow_shutter_inverted == 0
@@ -236,13 +236,13 @@ class Matter_Plugin_Shutter : Matter_Plugin_Device
matter_position = self.shadow_shutter_pos * 100
end
end
return tlv_solo.set_or_nil(0x05 #-TLV.U2-#, matter_position)
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, matter_position)
elif attribute == 0x000A # ---------- OperationalStatus / u8 ----------
var op
if self.shadow_shutter_direction != nil
op = self.shadow_shutter_direction == 0 ? 0 : (self.shadow_shutter_direction > 0 ? 1 : 2)
end
return tlv_solo.set_or_nil(0x04 #-TLV.U1-#, op)
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, op)
elif attribute == 0x000B # ---------- TargetPositionLiftPercent100ths / u16 ----------
if self.shadow_shutter_target != nil
if self.shadow_shutter_inverted == 0
@@ -251,10 +251,10 @@ class Matter_Plugin_Shutter : Matter_Plugin_Device
matter_position = self.shadow_shutter_target * 100
end
end
return tlv_solo.set_or_nil(0x05 #-TLV.U2-#, matter_position)
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, matter_position)
elif attribute == 0x0017 # ---------- Mode / u8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0) # normal mode
return tlv_solo.set(0x06 #-TLV.U4-#, 0) # normal mode
end
end
@@ -157,18 +157,18 @@ class Matter_Plugin_Thermostat : Matter_Plugin_Device
if self.shadow_local_temperature == nil
return tlv_solo.set(0x14 #-TLV.NULL-#, nil)
else
return tlv_solo.set(0x01 #-TLV.I2-#, self.shadow_local_temperature)
return tlv_solo.set(0x02 #-TLV.I4-#, self.shadow_local_temperature)
end
elif attribute == 0x0011 # OccupiedCoolingSetpoint / int16
return tlv_solo.set(0x01 #-TLV.I2-#, self.shadow_cooling_setpoint)
return tlv_solo.set(0x02 #-TLV.I4-#, self.shadow_cooling_setpoint)
elif attribute == 0x0012 # OccupiedHeatingSetpoint / int16
return tlv_solo.set(0x01 #-TLV.I2-#, self.shadow_heating_setpoint)
return tlv_solo.set(0x02 #-TLV.I4-#, self.shadow_heating_setpoint)
elif attribute == 0x001B # ControlSequenceOfOperation / enum8
return tlv_solo.set(0x04 #-TLV.U1-#, 4) # Cooling and heating
return tlv_solo.set(0x06 #-TLV.U4-#, 4) # Cooling and heating
elif attribute == 0x001C # SystemMode / enum8
return tlv_solo.set(0x04 #-TLV.U1-#, self.shadow_system_mode)
return tlv_solo.set(0x06 #-TLV.U4-#, self.shadow_system_mode)
elif attribute == 0x0029 # ThermostatRunningState / bitmap16
return tlv_solo.set(0x05 #-TLV.U2-#, self.shadow_running_state)
return tlv_solo.set(0x06 #-TLV.U4-#, self.shadow_running_state)
end
end
return super(self).read_attribute(session, ctx, tlv_solo)
@@ -272,15 +272,15 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0
if cluster == 0x0008 # ========== Level Control 1.6 p.57 ==========
self.update_shadow_lazy()
if attribute == 0x0000 # ---------- CurrentLevel / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, self.shadow_bri)
return tlv_solo.set(0x06 #-TLV.U4-#, self.shadow_bri)
elif attribute == 0x0002 # ---------- MinLevel / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0x0003 # ---------- MaxLevel / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 254)
return tlv_solo.set(0x06 #-TLV.U4-#, 254)
elif attribute == 0x000F # ---------- Options / map8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0) #
return tlv_solo.set(0x06 #-TLV.U4-#, 0) #
elif attribute == 0x0011 # ---------- OnLevel / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, self.shadow_bri)
return tlv_solo.set(0x06 #-TLV.U4-#, self.shadow_bri)
end
end
@@ -238,7 +238,7 @@ class Matter_Plugin_OnOff_Power : Matter_Plugin_OnOff
]
for s: specs
var e = acc.add_struct()
e.add_TLV(0, 0x04 #-TLV.U1-#, s[0]) # MeasurementType
e.add_TLV(0, 0x06 #-TLV.U4-#, s[0]) # MeasurementType
e.add_TLV(1, 0x08 #-TLV.BOOL-#, true) # Measured
e.add_TLV(2, 0x03 #-TLV.I8-#, s[1]) # MinMeasuredValue
e.add_TLV(3, 0x03 #-TLV.I8-#, s[2]) # MaxMeasuredValue
@@ -246,7 +246,7 @@ class Matter_Plugin_OnOff_Power : Matter_Plugin_OnOff
var r = ranges.add_struct()
r.add_TLV(0, 0x03 #-TLV.I8-#, s[1]) # RangeMin
r.add_TLV(1, 0x03 #-TLV.I8-#, s[2]) # RangeMax
r.add_TLV(2, 0x05 #-TLV.U2-#, 500) # PercentMax = 5.00%
r.add_TLV(2, 0x06 #-TLV.U4-#, 500) # PercentMax = 5.00%
end
return acc
end
@@ -261,9 +261,9 @@ class Matter_Plugin_OnOff_Power : Matter_Plugin_OnOff
# ====================================================================================================
if cluster == 0x0090 # ========== Electrical Power Measurement 2.13 ==========
if attribute == 0x0000 # ---------- PowerMode / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 2) # AC
return tlv_solo.set(0x06 #-TLV.U4-#, 2) # AC
elif attribute == 0x0001 # ---------- NumberOfMeasurementTypes / u8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 8)
return tlv_solo.set(0x06 #-TLV.U4-#, 8)
elif attribute == 0x0002 # ---------- Accuracy / list[MeasurementAccuracyStruct] ----------
return self._build_accuracy_list()
elif attribute == 0x0008 # ---------- ActivePower / i64 (mW) ----------
@@ -124,11 +124,11 @@ class Matter_Plugin_Sensor_Flow : Matter_Plugin_Sensor
# ====================================================================================================
if cluster == 0x0404 # ========== Flow Measurement 2.4 p.98 ==========
if attribute == 0x0000 # ---------- MeasuredValue / i16 ----------
return tlv_solo.set_or_nil(0x05 #-TLV.U2-#, int(self.shadow_value)) # MeasuredValue represents 10 x flow in m3/h.
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, int(self.shadow_value)) # MeasuredValue represents 10 x flow in m3/h.
elif attribute == 0x0001 # ---------- MinMeasuredValue / i16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0) # 0 m3/h
return tlv_solo.set(0x06 #-TLV.U4-#, 0) # 0 m3/h
elif attribute == 0x0002 # ---------- MaxMeasuredValue / i16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 65534) # 65534 m3/h
return tlv_solo.set(0x06 #-TLV.U4-#, 65534) # 65534 m3/h
end
end
@@ -133,11 +133,11 @@ class Matter_Plugin_Sensor_Humidity : Matter_Plugin_Sensor
# ====================================================================================================
if cluster == 0x0405 # ========== Humidity Measurement 2.4 p.98 ==========
if attribute == 0x0000 # ---------- Humidity / u16 ----------
return tlv_solo.set_or_nil(0x05 #-TLV.U2-#, int(self.shadow_value))
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, int(self.shadow_value))
elif attribute == 0x0001 # ---------- MinMeasuredValue / u16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 500) # 0%
return tlv_solo.set(0x06 #-TLV.U4-#, 500) # 0%
elif attribute == 0x0002 # ---------- MaxMeasuredValue / u16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 10000) # 100%
return tlv_solo.set(0x06 #-TLV.U4-#, 10000) # 100%
end
end
@@ -150,11 +150,11 @@ class Matter_Plugin_Sensor_Illuminance : Matter_Plugin_Sensor
# ====================================================================================================
if cluster == 0x0400 # ========== Illuminance Measurement 2.2 p.95 ==========
if attribute == 0x0000 # ---------- MeasuredValue / i16 ----------
return tlv_solo.set_or_nil(0x05 #-TLV.U2-#, int(self.shadow_value))
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, int(self.shadow_value))
elif attribute == 0x0001 # ---------- MinMeasuredValue / i16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 1) # 1 lux
return tlv_solo.set(0x06 #-TLV.U4-#, 1) # 1 lux
elif attribute == 0x0002 # ---------- MaxMeasuredValue / i16 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0xFFFE)
return tlv_solo.set(0x06 #-TLV.U4-#, 0xFFFE)
end
end
@@ -154,11 +154,11 @@ class Matter_Plugin_Sensor_Occupancy : Matter_Plugin_Sensor_Boolean
# ====================================================================================================
if cluster == 0x0406 # ========== Occupancy Sensing ==========
if attribute == 0x0000 # ---------- Occupancy / U8 ----------
return tlv_solo.set_or_nil(0x04 #-TLV.U1-#, self.shadow_bool_value)
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, self.shadow_bool_value)
elif attribute == 0x0001 # ---------- OccupancySensorType / enum8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 3) # physical contact
return tlv_solo.set(0x06 #-TLV.U4-#, 3) # physical contact
elif attribute == 0x0002 # ---------- OccupancySensorTypeBitmap / u8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0) # unknown
return tlv_solo.set(0x06 #-TLV.U4-#, 0) # unknown
end
end
@@ -135,11 +135,11 @@ class Matter_Plugin_Sensor_Pressure : Matter_Plugin_Sensor
# ====================================================================================================
if cluster == 0x0403 # ========== Pressure Measurement 2.4 p.98 ==========
if attribute == 0x0000 # ---------- MeasuredValue / i16 ----------
return tlv_solo.set_or_nil(0x01 #-TLV.I2-#, int(self.shadow_value))
return tlv_solo.set_or_nil(0x02 #-TLV.I4-#, int(self.shadow_value))
elif attribute == 0x0001 # ---------- MinMeasuredValue / i16 ----------
return tlv_solo.set(0x01 #-TLV.I2-#, 500) # 500 hPA
return tlv_solo.set(0x02 #-TLV.I4-#, 500) # 500 hPA
elif attribute == 0x0002 # ---------- MaxMeasuredValue / i16 ----------
return tlv_solo.set(0x01 #-TLV.I2-#, 1500) # 1500 hPA
return tlv_solo.set(0x02 #-TLV.I4-#, 1500) # 1500 hPA
end
end
@@ -143,11 +143,11 @@ class Matter_Plugin_Sensor_Temp : Matter_Plugin_Sensor
# ====================================================================================================
if cluster == 0x0402 # ========== Temperature Measurement 2.3 p.97 ==========
if attribute == 0x0000 # ---------- MeasuredValue / i16 (*100) ----------
return tlv_solo.set_or_nil(0x01 #-TLV.I2-#, self.shadow_value)
return tlv_solo.set_or_nil(0x02 #-TLV.I4-#, self.shadow_value)
elif attribute == 0x0001 # ---------- MinMeasuredValue / i16 (*100) ----------
return tlv_solo.set(0x01 #-TLV.I2-#, -5000) # -50 °C
return tlv_solo.set(0x02 #-TLV.I4-#, -5000) # -50 °C
elif attribute == 0x0002 # ---------- MaxMeasuredValue / i16 (*100) ----------
return tlv_solo.set(0x01 #-TLV.I2-#, 15000) # 150 °C
return tlv_solo.set(0x02 #-TLV.I4-#, 15000) # 150 °C
end
end
@@ -194,20 +194,20 @@ class Matter_Plugin_ShutterTilt : Matter_Plugin_Shutter
if cluster == 0x0102 # ========== Window Covering 5.3 p.289 ==========
self.update_shadow_lazy()
if attribute == 0x0007 # ---------- ConfigStatus / u8 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 1 + 8 + 16) # Operational + Lift Position Aware + Tilt Position Aware
return tlv_solo.set(0x06 #-TLV.U4-#, 1 + 8 + 16) # Operational + Lift Position Aware + Tilt Position Aware
elif attribute == 0x000F # ---------- CurrentPositionTiltPercent100ths / u8 ----------
self.update_tilt_min_max()
if self.tilt_min != nil && self.tilt_max != nil
var tilt_percentage = tasmota.scale_uint(self.shadow_shutter_tilt - self.tilt_min, 0, self.tilt_max - self.tilt_min, 0, 10000)
return tlv_solo.set(0x05 #-TLV.U2-#, tilt_percentage)
return tlv_solo.set(0x06 #-TLV.U4-#, tilt_percentage)
else
return tlv_solo.set(0x14 #-TLV.NULL-#, nil) # return invalid
end
elif attribute == 0x000C # ---------- TargetPositionTiltPercent100ths / u16 ----------
if self.tilt_min != nil && self.tilt_max != nil
var tilt_percentage = tasmota.scale_uint(self.shadow_shutter_tilt - self.tilt_min, 0, self.tilt_max - self.tilt_min, 0, 10000)
return tlv_solo.set(0x05 #-TLV.U2-#, tilt_percentage)
return tlv_solo.set(0x06 #-TLV.U4-#, tilt_percentage)
else
return tlv_solo.set(0x14 #-TLV.NULL-#, nil) # return invalid
end
@@ -212,23 +212,23 @@ class Matter_Plugin_Light2 : Matter_Plugin_Light1
if cluster == 0x0300 # ========== Color Control 3.2 p.111 ==========
self.update_shadow_lazy()
if attribute == 0x0007 # ---------- ColorTemperatureMireds / u2 ----------
return tlv_solo.set_or_nil(0x05 #-TLV.U2-#, self.shadow_ct) # if `nil` it is replaced with 0x14 #-TLV.NULL-#
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, self.shadow_ct) # if `nil` it is replaced with 0x14 #-TLV.NULL-#
elif attribute == 0x0008 # ---------- ColorMode / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 2) # 2 = ColorTemperatureMireds
return tlv_solo.set(0x06 #-TLV.U4-#, 2) # 2 = ColorTemperatureMireds
elif attribute == 0x000F # ---------- Options / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0x4001 # ---------- EnhancedColorMode / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 2) # 2 = ColorTemperatureMireds
return tlv_solo.set(0x06 #-TLV.U4-#, 2) # 2 = ColorTemperatureMireds
elif attribute == 0x400A # ---------- ColorCapabilities / map2 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0x10) # CT
return tlv_solo.set(0x06 #-TLV.U4-#, 0x10) # CT
elif attribute == 0x400B # ---------- ColorTempPhysicalMinMireds / u2 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, self.ct_min)
return tlv_solo.set(0x06 #-TLV.U4-#, self.ct_min)
elif attribute == 0x400C # ---------- ColorTempPhysicalMaxMireds / u2 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, self.ct_max)
return tlv_solo.set(0x06 #-TLV.U4-#, self.ct_max)
# Defined Primaries Information Attribute Set
elif attribute == 0x0010 # ---------- NumberOfPrimaries / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0xFFFC # ---------- FeatureMap / map32 ----------
return tlv_solo.set(0x06 #-TLV.U4-#, 0x10) # CT
@@ -234,21 +234,21 @@ class Matter_Plugin_Light3 : Matter_Plugin_Light1
if cluster == 0x0300 # ========== Color Control 3.2 p.111 ==========
self.update_shadow_lazy()
if attribute == 0x0000 # ---------- CurrentHue / u1 ----------
return tlv_solo.set_or_nil(0x04 #-TLV.U1-#, self.shadow_hue)
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, self.shadow_hue)
elif attribute == 0x0001 # ---------- CurrentSaturation / u2 ----------
return tlv_solo.set_or_nil(0x04 #-TLV.U1-#, self.shadow_sat)
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, self.shadow_sat)
elif attribute == 0x0008 # ---------- ColorMode / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0)# 0 = CurrentHue and CurrentSaturation
return tlv_solo.set(0x06 #-TLV.U4-#, 0)# 0 = CurrentHue and CurrentSaturation
elif attribute == 0x000F # ---------- Options / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0x4001 # ---------- EnhancedColorMode / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0x400A # ---------- ColorCapabilities / map2 ----------
return tlv_solo.set(0x05 #-TLV.U2-#, 0x01) # HS
return tlv_solo.set(0x06 #-TLV.U4-#, 0x01) # HS
# Defined Primaries Information Attribute Set
elif attribute == 0x0010 # ---------- NumberOfPrimaries / u1 ----------
return tlv_solo.set(0x04 #-TLV.U1-#, 0)
return tlv_solo.set(0x06 #-TLV.U4-#, 0)
elif attribute == 0xFFFC # ---------- FeatureMap / map32 ----------
return tlv_solo.set(0x06 #-TLV.U4-#, 0x01) # HS
@@ -149,7 +149,7 @@ class Matter_Plugin_Virt_HVAC : Matter_Plugin_Thermostat
var parts = TLV.Matter_TLV_array()
for pl: self.device.plugins
if pl.TYPE == "v_hvac_option" && pl.hvac_ep == self.endpoint
parts.add_TLV(nil, 0x05 #-TLV.U2-#, pl.endpoint)
parts.add_TLV(nil, 0x06 #-TLV.U4-#, pl.endpoint)
end
end
return parts
@@ -51,6 +51,8 @@ class Matter_TLV
# :----|:---
# I1 I2 I4|Signed integer of at most (1/2/4) bytes (as 32 bits signed Berry type)
# U1 U2 U4|Unsiged integer of at motst (1/2/4) bytes (as 32 bits signed Berry type, be careful when comparing. Use `matter.Counter.is_greater(a,b)`)
# |Convention: encode all signed ints with I4 (0x02) and all unsigned ints with U4 (0x06);
# |the encoder shrinks them to the smallest width. I1/I2/U1/U2 are never widened and truncate out-of-range values.
# I8 U8|Signed/insigned 8 bytes. You can pass `bytes(8)`, `int64()` or `int`. Type is collapsed to a lower type if possible when encoding.
# BOOL|boolean, takes `true` and `false`. Abstracts the internal `BTRUE` and `BFALSE` that you don't need to use
# FLOAT|32 bites float
@@ -174,7 +174,7 @@ class Matter_Device_BLE : Matter_Device
var cnresp = TLV.Matter_TLV_struct()
if r == "Successful"
cnresp.add_TLV(0, 0x04 #-TLV.U1-#, 0x00 #-SUCCESS-#)
cnresp.add_TLV(0, 0x06 #-TLV.U4-#, 0x00 #-SUCCESS-#)
cnresp.add_TLV(1, 0x0D #-TLV.UTF2-#, format("ip6=%s", tasmota.wifi()['ip6local']))
log("MTR: ConnectNetwork deferred -> Successful", 2)
global.matter_device.start()
@@ -193,7 +193,7 @@ class Matter_Device_BLE : Matter_Device
end
end
else
cnresp.add_TLV(0, 0x04 #-TLV.U1-#, 0x01 #-FAILURE-#)
cnresp.add_TLV(0, 0x06 #-TLV.U4-#, 0x01 #-FAILURE-#)
cnresp.add_TLV(1, 0x0D #-TLV.UTF2-#, format("wifi connect failed: %s", r))
log(f"MTR: ConnectNetwork deferred -> Failed: {r}", 2)
end