diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4c5d75448..dc6daa042 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
### Changed
- Berry `webclient.url_encode()` is now a static class method, no change required to existing code (#18775)
+- Matter Bridge mode always on
### Fixed
- Interaction of ``SetOption92``, ``VirtualCT``, and ``RGBWWTable`` (#18768)
diff --git a/lib/libesp32/berry_matter/src/be_matter_module.c b/lib/libesp32/berry_matter/src/be_matter_module.c
index b335cd147..bef0a4253 100644
--- a/lib/libesp32/berry_matter/src/be_matter_module.c
+++ b/lib/libesp32/berry_matter/src/be_matter_module.c
@@ -189,6 +189,7 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because
#include "../generate/be_matter_certs.h"
#include "solidify/solidified_Matter_Plugin_Root.h"
+#include "solidify/solidified_Matter_Plugin_Aggregator.h"
#include "solidify/solidified_Matter_Plugin_Device.h"
#include "solidify/solidified_Matter_Plugin_OnOff.h"
#include "solidify/solidified_Matter_Plugin_Light0.h"
@@ -388,6 +389,7 @@ module matter (scope: global, strings: weak) {
// Plugins
Plugin_Root, class(be_class_Matter_Plugin_Root) // Generic behavior common to all devices
+ Plugin_Aggregator, class(be_class_Matter_Plugin_Aggregator) // Aggregator
Plugin_Device, class(be_class_Matter_Plugin_Device) // Generic device (abstract)
Plugin_OnOff, class(be_class_Matter_Plugin_OnOff) // Relay/Light behavior (OnOff)
Plugin_Light0, class(be_class_Matter_Plugin_Light0) // OnOff Light
diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be
index 4db220670..4f4c215ca 100644
--- a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be
+++ b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be
@@ -680,13 +680,23 @@ class Matter_Device
var endpoints = self.k2l_num(config)
tasmota.log("MTR: endpoints to be configured "+str(endpoints), 3)
+ # start with mandatory endpoint 0 for root node
+ self.plugins.push(matter.Plugin_Root(self, 0, {}))
+ tasmota.log(string.format("MTR: endpoint:%i type:%s%s", 0, 'root', ''), 2)
+
+ # always include an aggregator for dynamic endpoints
+ self.plugins.push(matter.Plugin_Aggregator(self, 0xFF00, {}))
+ tasmota.log(string.format("MTR: endpoint:%i type:%s%s", 0xFF00, 'aggregator', ''), 2)
+
for ep: endpoints
+ if ep == 0 continue end # skip endpoint 0
try
var plugin_conf = config[str(ep)]
tasmota.log(string.format("MTR: endpoint %i config %s", ep, plugin_conf), 3)
var pi_class_name = plugin_conf.find('type')
if pi_class_name == nil tasmota.log("MTR: no class name, skipping", 3) continue end
+ if pi_class_name == 'root' tasmota.log("MTR: only one root node allowed", 3) continue end
var pi_class = self.plugins_classes.find(pi_class_name)
if pi_class == nil tasmota.log("MTR: unknown class name '"+str(pi_class_name)+"' skipping", 2) continue end
@@ -1004,9 +1014,6 @@ class Matter_Device
import json
var m = {}
- # add the default plugin
- m["0"] = {'type':'root'}
-
# check if we have a light
var endpoint = 1
var light_present = false
diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be
index 03e8d8734..dafeb7793 100644
--- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be
+++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be
@@ -36,6 +36,7 @@ class Matter_Plugin
# Configuration of the plugin: clusters and type
static var CLUSTERS = {
0x001D: [0,1,2,3,0xFFFC,0xFFFD], # Descriptor Cluster 9.5 p.453
+ 0x0039: [0x11], # Bridged Device Basic Information 9.13 p.485
}
var device # reference to the `device` global object
var endpoint # current endpoint
@@ -180,6 +181,12 @@ class Matter_Plugin
return TLV.create_TLV(TLV.U4, 1) # "Initial Release"
end
+ # ====================================================================================================
+ elif cluster == 0x0039 # ========== Bridged Device Basic Information 9.13 p.485 ==========
+
+ if attribute == 0x0011 # ---------- Reachable / bool ----------
+ return TLV.create_TLV(TLV.BOOL, 1) # by default we are reachable
+ end
else
return nil
end
diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Aggregator.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Aggregator.be
new file mode 100644
index 000000000..90a9255ac
--- /dev/null
+++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Aggregator.be
@@ -0,0 +1,71 @@
+#
+# Matter_Plugin_Aggregator.be - implements the Aggregator endpoint
+#
+# Copyright (C) 2023 Stephan Hadinger & Theo Arends
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import matter
+
+# Matter plug-in for root behavior
+
+# dummy declaration for solidification
+class Matter_Plugin end
+
+#@ solidify:Matter_Plugin_Aggregator,weak
+
+class Matter_Plugin_Aggregator : Matter_Plugin
+ static var TYPE = "aggregator" # name of the plug-in in json
+ static var NAME = "Aggregator" # display name of the plug-in
+# static var CLUSTERS = {
+# # 0x001D: inherited # Descriptor Cluster 9.5 p.453
+# }
+ static var TYPES = { 0x000E: 1 } # Aggregator
+
+ #############################################################
+ # read an attribute
+ #
+ def read_attribute(session, ctx)
+ import string
+ var TLV = matter.TLV
+ var cluster = ctx.cluster
+ var attribute = ctx.attribute
+
+ if cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ==========
+
+ # overwrite PartsList
+ if attribute == 0x0003 # ---------- PartsList / list[endpoint-no]----------
+ var pl = TLV.Matter_TLV_array()
+ var eps = self.device.get_active_endpoints(true)
+ for ep: eps
+ if ep != 0xFF00
+ pl.add_TLV(nil, TLV.U2, ep) # add each endpoint
+ end
+ end
+ return pl
+ else
+ return super(self).read_attribute(session, ctx)
+ end
+
+ else
+ return super(self).read_attribute(session, ctx)
+
+ end
+ # no match found, return that the attribute is unsupported
+ end
+
+end
+matter.Plugin_Aggregator = Matter_Plugin_Aggregator
+
\ No newline at end of file
diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_HTTP.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_HTTP.be
index 3918882ad..12c487449 100644
--- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_HTTP.be
+++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_HTTP.be
@@ -43,7 +43,7 @@ class Matter_Plugin_Bridge_HTTP : Matter_Plugin_Device
# 0x0006: [0,0xFFFC,0xFFFD], # On/Off 1.5 p.48
# 0x0028: [0,1,2,3,4,5,6,7,8,9,0x0A,0x0F,0x12,0x13],# Basic Information Cluster cluster 11.1 p.565
- 0x0039: [0x11] # Bridged Device Basic Information 9.13 p.485
+ # 0x0039: [0x11] # Bridged Device Basic Information 9.13 p.485
}
# static var TYPES = { 0x010A: 2 } # On/Off Light
@@ -176,9 +176,7 @@ class Matter_Plugin_Bridge_HTTP : Matter_Plugin_Device
# ====================================================================================================
if cluster == 0x0039 # ========== Bridged Device Basic Information 9.13 p.485 ==========
- if attribute == 0x0000 # ---------- DataModelRevision / CommissioningWindowStatus ----------
- # return TLV.create_TLV(TLV.U2, 1)
- elif attribute == 0x0011 # ---------- Reachable / bool ----------
+ if attribute == 0x0011 # ---------- Reachable / bool ----------
# self.is_reachable_lazy_sync() # Not needed anymore
return TLV.create_TLV(TLV.BOOL, self.http_remote.reachable) # TODO find a way to do a ping
end
diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_OnOff.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_OnOff.be
new file mode 100644
index 000000000..be1184866
--- /dev/null
+++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_OnOff.be
@@ -0,0 +1,97 @@
+#
+# Matter_Plugin_Sensor_OnOff.be - implements the behavior for a Occupany Switch
+#
+# Copyright (C) 2023 Stephan Hadinger & Theo Arends
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# Matter plug-in for core behavior
+
+# dummy declaration for solidification
+class Matter_Plugin_Device end
+
+#@ solidify:Matter_Plugin_Sensor_OnOff,weak
+
+class Matter_Plugin_Sensor_OnOff : Matter_Plugin_Device
+ static var TYPE = "occupancy" # name of the plug-in in json
+ static var NAME = "OnOff" # display name of the plug-in
+ static var ARG = "switch" # additional argument name (or empty if none)
+ static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type
+ static var UPDATE_TIME = 5000 # update every 250ms
+ static var CLUSTERS = {
+ 0x0006: [0,0xFFFC,0xFFFD], # On/Off 1.5 p.48
+ }
+ static var TYPES = { 0x0850: 2 } # OnOff Sensor, rev 2
+
+ var tasmota_switch_index # Switch number in Tasmota (one based)
+ var shadow_onoff
+
+ #############################################################
+ # Constructor
+ def init(device, endpoint, arguments)
+ super(self).init(device, endpoint, arguments)
+ self.tasmota_switch_index = int(arguments.find(self.ARG #-'relay'-#, 1))
+ if self.tasmota_switch_index <= 0 self.tasmota_switch_index = 1 end
+ end
+
+ #############################################################
+ # Update shadow
+ #
+ def update_shadow()
+ super(self).update_shadow()
+
+ import json
+ var ret = tasmota.cmd("Status 8", true)
+ if ret != nil
+ var j = json.load(ret)
+ if j != nil
+ var state = false
+ state = (j.find("Switch" + str(self.tasmota_switch_index)) == "ON")
+
+ if self.shadow_onoff != nil && self.shadow_onoff != bool(state)
+ self.attribute_updated(0x0406, 0x0000)
+ end
+ self.shadow_onoff = state
+ end
+ end
+ end
+
+ #############################################################
+ # read an attribute
+ #
+ def read_attribute(session, ctx)
+ import string
+ var TLV = matter.TLV
+ var cluster = ctx.cluster
+ var attribute = ctx.attribute
+
+ # ====================================================================================================
+ if cluster == 0x0006 # ========== On/Off 1.5 p.48 ==========
+ self.update_shadow_lazy()
+ if attribute == 0x0000 # ---------- OnOff / bool ----------
+ return TLV.create_TLV(TLV.BOOL, self.shadow_onoff)
+ elif attribute == 0xFFFC # ---------- FeatureMap / map32 ----------
+ return TLV.create_TLV(TLV.U4, 0) # 0 = no Level Control for Lighting
+ elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ----------
+ return TLV.create_TLV(TLV.U4, 4) # 0 = no Level Control for Lighting
+ end
+
+ else
+ return super(self).read_attribute(session, ctx)
+ end
+ end
+
+end
+matter.Plugin_Sensor_OnOff = Matter_Plugin_Sensor_OnOff
diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be
index a59955ded..769a458c9 100644
--- a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be
+++ b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be
@@ -32,7 +32,6 @@ import matter
# WebUI for the partition manager
#################################################################################
class Matter_UI
- static var _ROOT_TYPES = "root"
static var _CLASSES_TYPES = "|relay|light0|light1|light2|light3|shutter|shutter+tilt"
"|temperature|pressure|illuminance|humidity|occupancy"
static var _CLASSES_TYPES2= "-http|http_relay|http_light0|http_light1|http_light2|http_light3"
@@ -164,6 +163,15 @@ class Matter_UI
import string
webserver.content_send("