Skip to content

Commit

Permalink
Matter add friendly-name (NodeLabel) to each endpoint (#18897)
Browse files Browse the repository at this point in the history
  • Loading branch information
s-hadinger authored Jun 18, 2023
1 parent b2fd311 commit 4a3b645
Show file tree
Hide file tree
Showing 33 changed files with 3,095 additions and 2,103 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
- Matter redesigned UI
- Matter add support for Contact Sensor
- Berry `string.format()` now automatically converts type according to format
- Matter add friendly-name (NodeLabel) to each endpoint

### Breaking Changed

Expand Down
10 changes: 5 additions & 5 deletions lib/libesp32/berry_matter/src/embedded/Matter_Device.be
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ class Matter_Device
var param_log = ''
for k:_class.k2l(plugin_conf)
if k == 'type' continue end
param_log += string.format(" %s = %s", k, plugin_conf[k])
param_log += string.format(" %s:%s", k, plugin_conf[k])
end
return param_log
end
Expand All @@ -718,7 +718,7 @@ class Matter_Device

# start with mandatory endpoint 0 for root node
self.plugins.push(matter.Plugin_Root(self, 0, {}))
tasmota.log(string.format("MTR: endpoint = %5i type = %s%s", 0, 'root', ''), 2)
tasmota.log(string.format("MTR: endpoint = %5i type:%s%s", 0, 'root', ''), 2)

# always include an aggregator for dynamic endpoints
self.plugins.push(matter.Plugin_Aggregator(self, 0xFF00, {}))
Expand All @@ -738,12 +738,12 @@ class Matter_Device
var pi = pi_class(self, ep, plugin_conf)
self.plugins.push(pi)

tasmota.log(string.format("MTR: endpoint = %5i type = %s%s", ep, pi_class_name, self.conf_to_log(plugin_conf)), 2)
tasmota.log(string.format("MTR: endpoint = %5i type:%s%s", ep, pi_class_name, self.conf_to_log(plugin_conf)), 2)
except .. as e, m
tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2)
end
end
tasmota.log(string.format("MTR: endpoint = %5i type = %s%s", 0xFF00, 'aggregator', ''), 2)
tasmota.log(string.format("MTR: endpoint = %5i type:%s%s", 0xFF00, 'aggregator', ''), 2)

tasmota.publish_result('{"Matter":{"Initialized":1}}', 'Matter')
end
Expand Down Expand Up @@ -1260,7 +1260,7 @@ class Matter_Device
pi_conf[k] = plugin_conf[k]
end
# add to main
tasmota.log(string.format("MTR: adding endpoint = %i type = %s%s", ep, pi_class_name, self.conf_to_log(plugin_conf)), 2)
tasmota.log(string.format("MTR: adding endpoint = %i type:%s%s", ep, pi_class_name, self.conf_to_log(plugin_conf)), 2)
self.plugins_config[ep_str] = pi_conf
self.plugins_persist = true
self.next_ep += 1 # increment next allocated endpoint before saving
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import matter
# dummy declaration for solidification
class Matter_Plugin_Device end

#@ solidify:Matter_Plugin_Bridge_HTTP.GetOptionReader,weak
#@ solidify:Matter_Plugin_Bridge_HTTP,weak

class Matter_Plugin_Bridge_HTTP : Matter_Plugin_Device
Expand Down Expand Up @@ -209,15 +210,73 @@ class Matter_Plugin_Bridge_HTTP : Matter_Plugin_Device
# web_values
#
# Show values of the remote device as HTML
static var PREFIX = "| <i>%s</i> "
def web_values()
import webserver
webserver.content_send("| &lt;-- (" + self.NAME + ") --&gt;")
import string
self.web_values_prefix()
webserver.content_send("&lt;-- (" + self.NAME + ") --&gt;")
end

# Show prefix before web value
def web_values_prefix()
import webserver
import string
var name = self.get_name()
webserver.content_send(string.format(self.PREFIX, name ? webserver.html_escape(name) : ""))
end

# Show on/off value as html
def web_value_onoff(onoff)
var onoff_html = (onoff != nil ? (onoff ? "<b>On</b>" : "Off") : "")
return onoff_html
end

#############################################################
# GetOption reader to decode `SetOption<x>` values from `Status 3`
static class GetOptionReader
var flag, flag2, flag3, flag4, flag5, flag6

def init(j)
if j == nil raise "value_error", "invalid json" end
var so = j['SetOption']
self.flag = bytes().fromhex(so[0]).reverse()
self.flag2 = bytes().fromhex(so[1])
self.flag3 = bytes().fromhex(so[2]).reverse()
self.flag4 = bytes().fromhex(so[3]).reverse()
self.flag5 = bytes().fromhex(so[4]).reverse()
self.flag6 = bytes().fromhex(so[5]).reverse()
end
def getoption(x)
if x < 32 # SetOption0 .. 31 = Settings->flag
return self.flag.getbits(x, 1)
elif x < 50 # SetOption32 .. 49 = Settings->param
return self.flag2.get(x - 32, 1)
elif x < 82 # SetOption50 .. 81 = Settings->flag3
return self.flag3.getbits(x - 50, 1)
elif x < 114 # SetOption82 .. 113 = Settings->flag4
return self.flag4.getbits(x - 82, 1)
elif x < 146 # SetOption114 .. 145 = Settings->flag5
return self.flag5.getbits(x - 114, 1)
elif x < 178 # SetOption146 .. 177 = Settings->flag6
return self.flag6.getbits(x - 146, 1)
end
end
end

#- Examples
import json
var p = '{"SerialLog":2,"WebLog":3,"MqttLog":0,"SysLog":0,"LogHost":"","LogPort":514,"SSId":["Livebox-781A",""],"TelePeriod":300,"Resolution":"558180C0","SetOption":["00008009","2805C80001800600003C5A0A192800000000","00000080","00006000","00006000","00000020"]}'
var j = json.load(p)
var gor = matter.Plugin_Bridge_HTTP.GetOptionReader(j)
assert(gor.getoption(151) == 1)
assert(gor.getoption(150) == 0)
assert(gor.getoption(32) == 40)
assert(gor.getoption(37) == 128)
-#
end
matter.Plugin_Bridge_HTTP = Matter_Plugin_Bridge_HTTP
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,19 @@ class Matter_Plugin_Bridge_Light0 : Matter_Plugin_Bridge_HTTP
def web_values()
import webserver
import string
webserver.content_send(string.format("| Light %s", self.web_value_onoff(self.shadow_onoff)))
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("%s", self.web_value_onoff(self.shadow_onoff)))
end

# Show prefix before web value
def web_values_prefix()
import webserver
import string
var name = self.get_name()
if !name
name = "Power" + str(self.tasmota_relay_index)
end
webserver.content_send(string.format(self.PREFIX, name ? webserver.html_escape(name) : ""))
end

end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ class Matter_Plugin_Bridge_Light1 : Matter_Plugin_Bridge_Light0
def web_values()
import webserver
import string
webserver.content_send(string.format("| Light %s %s", self.web_value_onoff(self.shadow_onoff), self.web_value_dimmer()))
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("%s %s", self.web_value_onoff(self.shadow_onoff), self.web_value_dimmer()))
end

# Show on/off value as html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ class Matter_Plugin_Bridge_Light2 : Matter_Plugin_Bridge_Light1
def web_values()
import webserver
import string
webserver.content_send(string.format("| Light %s %s %s",
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("%s %s %s",
self.web_value_onoff(self.shadow_onoff), self.web_value_dimmer(),
self.web_value_ct()))
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1
def web_values()
import webserver
import string
webserver.content_send(string.format("| Light %s %s %s",
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("%s %s %s",
self.web_value_onoff(self.shadow_onoff), self.web_value_dimmer(),
self.web_value_RGB()))
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class Matter_Plugin_Bridge_OnOff : Matter_Plugin_Bridge_Light0
def web_values()
import webserver
import string
webserver.content_send(string.format("| Relay %i %s", self.tasmota_relay_index, self.web_value_onoff(self.shadow_onoff)))
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("Relay %i %s", self.tasmota_relay_index, self.web_value_onoff(self.shadow_onoff)))
end

end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,14 @@ class Matter_Plugin_Bridge_Sensor : Matter_Plugin_Bridge_HTTP
return ""
end

# Show prefix before web value
def web_values_prefix()
import webserver
import string
var name = self.get_name()
if (!name) name = self.filter_name_html() end
webserver.content_send(string.format(self.PREFIX, name ? webserver.html_escape(name) : ""))
end

end
matter.Plugin_Bridge_Sensor = Matter_Plugin_Bridge_Sensor
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,19 @@ class Matter_Plugin_Bridge_Sensor_Contact : Matter_Plugin_Bridge_HTTP
def web_values()
import webserver
import string
webserver.content_send(string.format("| Contact%i %s", self.tasmota_switch_index, self.web_value_onoff(self.shadow_contact)))
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("Contact%i %s", self.tasmota_switch_index, self.web_value_onoff(self.shadow_contact)))
end

# Show prefix before web value
def web_values_prefix()
import webserver
import string
var name = self.get_name()
if !name
name = "Switch" + str(self.tasmota_switch_index)
end
webserver.content_send(string.format(self.PREFIX, name ? webserver.html_escape(name) : ""))
end
end
matter.Plugin_Bridge_Sensor_Contact = Matter_Plugin_Bridge_Sensor_Contact
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class Matter_Plugin_Bridge_Sensor_Humidity : Matter_Plugin_Bridge_Sensor
def web_values()
import webserver
import string
webserver.content_send(string.format("| %s &#x1F4A7; %2.0f%%",
self.filter_name_html(),
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("&#x1F4A7; %2.0f%%",
self.shadow_value != nil ? real(self.shadow_value) / 100 : nil))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ class Matter_Plugin_Bridge_Sensor_Illuminance : Matter_Plugin_Bridge_Sensor
def web_values()
import webserver
import string
webserver.content_send(string.format("| %s &#128261; %ilux",
self.filter_name_html(),
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("&#128261; %ilux",
int(self.shadow_value)))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,19 @@ class Matter_Plugin_Bridge_Sensor_Occupancy : Matter_Plugin_Bridge_HTTP
def web_values()
import webserver
import string
webserver.content_send(string.format("| Occupancy%i %s", self.tasmota_switch_index, self.web_value_onoff(self.shadow_occupancy)))
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("Occupancy%i %s", self.tasmota_switch_index, self.web_value_onoff(self.shadow_occupancy)))
end

# Show prefix before web value
def web_values_prefix()
import webserver
import string
var name = self.get_name()
if !name
name = "Switch" + str(self.tasmota_switch_index)
end
webserver.content_send(string.format(self.PREFIX, name ? webserver.html_escape(name) : ""))
end
end
matter.Plugin_Bridge_Sensor_Occupancy = Matter_Plugin_Bridge_Sensor_Occupancy
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class Matter_Plugin_Bridge_Sensor_Pressure : Matter_Plugin_Bridge_Sensor
def web_values()
import webserver
import string
webserver.content_send(string.format("| %s &#x26C5; %i hPa",
self.filter_name_html(),
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("&#x26C5; %i hPa",
int(self.shadow_value)))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class Matter_Plugin_Bridge_Sensor_Temp : Matter_Plugin_Bridge_Sensor
def web_values()
import webserver
import string
webserver.content_send(string.format("| %s &#x2600;&#xFE0F; %.1f °C",
self.filter_name_html(),
self.web_values_prefix() # display '| ' and name if present
webserver.content_send(string.format("&#x2600;&#xFE0F; %.1f °C",
self.shadow_value != nil ? real(self.shadow_value) / 100 : nil))
end

Expand Down
30 changes: 25 additions & 5 deletions lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Device.be
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,30 @@ class Matter_Plugin end
class Matter_Plugin_Device : Matter_Plugin
static var CLUSTERS = {
# 0x001D: inherited # Descriptor Cluster 9.5 p.453
0x0039: [0x11], # Bridged Device Basic Information 9.13 p.485
0x0039: [5], # Bridged Device Basic Information 9.13 p.485
0x0003: [0,1,0xFFFC,0xFFFD], # Identify 1.2 p.16
0x0004: [0,0xFFFC,0xFFFD], # Groups 1.3 p.21
0x0005: [0,1,2,3,4,5,0xFFFC,0xFFFD], # Scenes 1.4 p.30 - no writable
}
static var TYPES = { 0x0013: 1 } # fake type
static var NON_BRIDGE_VENDOR = [ 0x1217, 0x1381 ] # Fabric VendorID not supporting Bridge mode

var node_label # name of the endpoint, used only in bridge mode, "" if none

def set_name(n)
if n != self.node_label
self.attribute_updated(0x0039, 0x0005)
end
self.node_label = n
end
def get_name() return self.node_label end

#############################################################
# Constructor
# def init(device, endpoint, arguments)
# super(self).init(device, endpoint, arguments)
# end
def init(device, endpoint, config)
self.node_label = config.find("name", "")
super(self).init(device, endpoint, config)
end

#############################################################
# read an attribute
Expand Down Expand Up @@ -103,7 +114,16 @@ class Matter_Plugin_Device : Matter_Plugin
else
return super(self).read_attribute(session, ctx)
end


# ====================================================================================================
elif cluster == 0x0039 # ========== Bridged Device Basic Information 9.13 p.485 ==========

if attribute == 0x0005 # ---------- NodeLabel / string ----------
return TLV.create_TLV(TLV.UTF1, self.get_name())
else
return super(self).read_attribute(session, ctx)
end

else
return super(self).read_attribute(session, ctx)
end
Expand Down
Loading

0 comments on commit 4a3b645

Please sign in to comment.