Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matter add friendly-name (NodeLabel) to each endpoint #18897

Merged
merged 1 commit into from
Jun 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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