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 events phase 1 #19484

Merged
merged 1 commit into from
Sep 9, 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
2 changes: 2 additions & 0 deletions lib/libesp32/berry_matter/src/be_matter_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ BE_FUNC_CTYPE_DECLARE(matter_get_command_name, "s", "ii")
extern const void* matter_get_ip_bytes(const char* ip_str, size_t* ret_len);
BE_FUNC_CTYPE_DECLARE(matter_get_ip_bytes, "&", "s")

extern int matter_publish_command(bvm *vm);

#include "solidify/solidified_Matter_inspect.h"

Expand Down Expand Up @@ -276,6 +277,7 @@ module matter (scope: global, strings: weak) {
setmember, closure(matter_setmember_closure)
member, closure(matter_member_closure)
get_ip_bytes, ctype_func(matter_get_ip_bytes)
publish_command, func(matter_publish_command)

get_vendor_name, ctype_func(matter_get_vendor_name)
get_cluster_name, ctype_func(matter_get_cluster_name)
Expand Down
7 changes: 3 additions & 4 deletions lib/libesp32/berry_matter/src/embedded/Matter_IM.be
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ class Matter_IM
var res = self.device.invoke_request(msg.session, q.command_fields, ctx)
matter.profiler.log("COMMAND DONE")
var params_log = (ctx.log != nil) ? "(" + str(ctx.log) + ") " : ""
tasmota.log(format("MTR: >Command (%6i) %s %s %s", msg.session.local_session_id, ctx_str, cmd_name ? cmd_name : "", params_log), ctx.endpoint != 0 ? 2 : 3 #- don't log for endpoint 0 -# )
tasmota.log(format("MTR: >Command (%6i) %s %s %s", msg.session.local_session_id, ctx_str, cmd_name ? cmd_name : "", params_log), 3)
# tasmota.log("MTR: Perf/Command = " + str(debug.counters()), 4)
ctx.log = nil
var raw = bytes(32)
Expand Down Expand Up @@ -927,9 +927,8 @@ class Matter_IM
var res = self.device.invoke_request(msg.session, ctx.command_fields, ctx)
matter.profiler.log("COMMAND DONE")
var params_log = (ctx.log != nil) ? "(" + str(ctx.log) + ") " : ""
var cmd_log_level = ctx.endpoint != 0 ? 2 : 3 #- don't log for endpoint 0 -#
if tasmota.loglevel(cmd_log_level)
tasmota.log(format("MTR: >Command1 (%6i) %s %s %s", msg.session.local_session_id, ctx_str, cmd_name ? cmd_name : "", params_log), cmd_log_level)
if tasmota.loglevel(3)
tasmota.log(format("MTR: >Command1 (%6i) %s %s %s", msg.session.local_session_id, ctx_str, cmd_name ? cmd_name : "", params_log), 3)
end
# tasmota.log("MTR: Perf/Command = " + str(debug.counters()), 4)
ctx.log = nil
Expand Down
26 changes: 26 additions & 0 deletions lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Matter_Plugin
var endpoint # current endpoint
var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy
var tick # tick value when it was last updated
var node_label # name of the endpoint, used only in bridge mode, "" if none

#############################################################
# MVC Model
Expand All @@ -61,6 +62,7 @@ class Matter_Plugin
self.endpoint = endpoint
self.clusters = self.consolidate_clusters()
self.parse_configuration(config)
self.node_label = config.find("name", "")
end

# proxy for the same method in IM
Expand Down Expand Up @@ -146,6 +148,22 @@ class Matter_Plugin
return ret
end

#############################################################
# Publish to MQTT a command received from controller
#
# we limit to 3 commands (to we need more?)
def publish_command(key1, value1, key2, value2, key3, value3)
import json
var payload = f"{json.dump(key1)}:{json.dump(value1)}"
if key2 != nil
payload = f"{payload},{json.dump(key2)}:{json.dump(value2)}"
end
if key3 != nil
payload = f"{payload},{json.dump(key3)}:{json.dump(value3)}"
end
matter.publish_command('MtrReceived', self.endpoint, self.node_label, payload)
end

#############################################################
# Which endpoints does it handle (list of numbers)
def get_endpoint()
Expand Down Expand Up @@ -184,6 +202,14 @@ class Matter_Plugin
return self.clusters.contains(cluster) && self.endpoints.find(endpoint) != nil
end

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

#############################################################
# MVC Model
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,15 @@ class Matter_Plugin_Bridge_Light0 : Matter_Plugin_Bridge_HTTP
if cluster == 0x0006 # ========== On/Off 1.5 p.48 ==========
if command == 0x0000 # ---------- Off ----------
self.set_onoff(false)
self.publish_command('Power', 0)
return true
elif command == 0x0001 # ---------- On ----------
self.set_onoff(true)
self.publish_command('Power', 1)
return true
elif command == 0x0002 # ---------- Toggle ----------
self.set_onoff(!self.shadow_onoff)
self.publish_command('Power', self.shadow_onoff ? 1 : 0)
return true
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ class Matter_Plugin_Bridge_Light1 : Matter_Plugin_Bridge_Light0
var bri_in = val.findsubval(0) # Hue 0..254
self.set_bri(bri_in)
ctx.log = "bri:"+str(bri_in)
self.publish_command('Bri', tasmota.scale_uint(bri_in, 0, 254, 0, 255),
'Dimmer', tasmota.scale_uint(bri_in, 0, 254, 0, 100))
return true
elif command == 0x0001 # ---------- Move ----------
# TODO, we don't really support it
Expand All @@ -147,6 +149,9 @@ class Matter_Plugin_Bridge_Light1 : Matter_Plugin_Bridge_Light0
var onoff = bri_in > 0
self.set_onoff(onoff)
ctx.log = "bri:"+str(bri_in)
self.publish_command('Bri', tasmota.scale_uint(bri_in, 0, 254, 0, 255),
'Dimmer', tasmota.scale_uint(bri_in, 0, 254, 0, 100),
'Power', onoff ? 1 : 0)
return true
elif command == 0x0005 # ---------- MoveWithOnOff ----------
# TODO, we don't really support it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class Matter_Plugin_Bridge_Light2 : Matter_Plugin_Bridge_Light1
if ct_in > self.ct_max ct_in = self.ct_max end
self.set_ct(ct_in)
ctx.log = "ct:"+str(ct_in)
self.publish_command('CT', ct_in)
return true
elif command == 0x0047 # ---------- StopMoveStep ----------
# TODO, we don't really support it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1
var hue_in = val.findsubval(0) # Hue 0..254
self.set_hue(hue_in)
ctx.log = "hue:"+str(hue_in)
self.publish_command('Hue', hue_in)
return true
elif command == 0x0001 # ---------- MoveHue ----------
# TODO, we don't really support it
Expand All @@ -168,6 +169,7 @@ class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1
var sat_in = val.findsubval(0) # Sat 0..254
self.set_sat(sat_in)
ctx.log = "sat:"+str(sat_in)
self.publish_command('Sat', sat_in)
return true
elif command == 0x0004 # ---------- MoveSaturation ----------
# TODO, we don't really support it
Expand All @@ -181,6 +183,7 @@ class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1
self.set_hue(hue_in)
self.set_sat(sat_in)
ctx.log = "hue:"+str(hue_in)+" sat:"+str(sat_in)
self.publish_command('Hue', hue_in, 'Sat', sat_in)
return true
elif command == 0x0047 # ---------- StopMoveStep ----------
# TODO, we don't really support it
Expand Down
19 changes: 8 additions & 11 deletions lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Device.be
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,18 @@ class Matter_Plugin_Device : Matter_Plugin
}
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
# Inherited
# var device # reference to the `device` global object
# var endpoint # current endpoint
# var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy
# var tick # tick value when it was last updated
# var node_label # name of the endpoint, used only in bridge mode, "" if none
var virtual # (bool) is the device pure virtual (i.e. not related to a device implementation by Tasmota)

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

Expand Down
49 changes: 37 additions & 12 deletions lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light0.be
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ class Matter_Plugin_Light0 : Matter_Plugin_Device
}
static var TYPES = { 0x0100: 2 } # OnOff Light, but not actually used because Relay is managed by OnOff

var shadow_onoff
# Inherited
# var device # reference to the `device` global object
# var endpoint # current endpoint
# var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy
# var tick # tick value when it was last updated
# var node_label # name of the endpoint, used only in bridge mode, "" if none
# var virtual # (bool) is the device pure virtual (i.e. not related to a device implementation by Tasmota)
var shadow_onoff # (bool) status of the light power on/off

#############################################################
# Constructor
Expand All @@ -52,15 +59,33 @@ class Matter_Plugin_Light0 : Matter_Plugin_Device
# Update shadow
#
def update_shadow()
import light
var light_status = light.get()
if light_status != nil
var pow = light_status.find('power', nil)
if pow != self.shadow_onoff self.attribute_updated(0x0006, 0x0000) self.shadow_onoff = pow end
if !self.virtual
import light
var light_status = light.get()
if light_status != nil
var pow = light_status.find('power', nil)
if pow != self.shadow_onoff
self.attribute_updated(0x0006, 0x0000)
self.shadow_onoff = pow
end
end
end
super(self).update_shadow()
end

def set_onoff(pow)
if !self.virtual
import light
light.set({'power':pow})
self.update_shadow()
else
if pow != self.shadow_onoff
self.attribute_updated(0x0006, 0x0000)
self.shadow_onoff = pow
end
end
end

#############################################################
# read an attribute
#
Expand Down Expand Up @@ -100,16 +125,16 @@ class Matter_Plugin_Light0 : Matter_Plugin_Device
if cluster == 0x0006 # ========== On/Off 1.5 p.48 ==========
self.update_shadow_lazy()
if command == 0x0000 # ---------- Off ----------
light.set({'power':false})
self.update_shadow()
self.set_onoff(false)
self.publish_command('Power', 0)
return true
elif command == 0x0001 # ---------- On ----------
light.set({'power':true})
self.update_shadow()
self.set_onoff(true)
self.publish_command('Power', 1)
return true
elif command == 0x0002 # ---------- Toggle ----------
light.set({'power':!self.shadow_onoff})
self.update_shadow()
self.set_onoff(!self.shadow_onoff)
self.publish_command('Power', self.shadow_onoff ? 1 : 0)
return true
end
end
Expand Down
80 changes: 58 additions & 22 deletions lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light1.be
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,15 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0
}
static var TYPES = { 0x0101: 2 } # Dimmable Light

var shadow_bri
# var shadow_onoff # inherited
# Inherited
# var device # reference to the `device` global object
# var endpoint # current endpoint
# var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy
# var tick # tick value when it was last updated
# var node_label # name of the endpoint, used only in bridge mode, "" if none
# var virtual # (bool) is the device pure virtual (i.e. not related to a device implementation by Tasmota)
# var shadow_onoff # (bool) status of the light power on/off
var shadow_bri # (int 0..254) brightness before Gamma correction - as per Matter 255 is not allowed

#############################################################
# Constructor
Expand All @@ -53,21 +60,52 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0
# Update shadow
#
def update_shadow()
import light
var light_status = light.get()
if light_status != nil
var bri = light_status.find('bri', nil)
if bri != nil
bri = tasmota.scale_uint(bri, 0, 255, 0, 254)
if bri != self.shadow_bri
self.attribute_updated(0x0008, 0x0000)
self.shadow_bri = bri
if !self.virtual
import light
var light_status = light.get()
if light_status != nil
var bri = light_status.find('bri', nil)
if bri != nil
bri = tasmota.scale_uint(bri, 0, 255, 0, 254)
if bri != self.shadow_bri
self.attribute_updated(0x0008, 0x0000)
self.shadow_bri = bri
end
end
end
end
super(self).update_shadow() # superclass manages 'power'
end

#############################################################
# Set Bri
#
# `bri` is in range 0.255 and not 0..254 like in Matter
# `pow` can be bool on `nil` if no change
def set_bri(bri_254, pow)
if (bri_254 < 0) bri_254 = 0 end
if (bri_254 > 254) bri_254 = 254 end
if !self.virtual
import light
var bri_255 = tasmota.scale_uint(bri_254, 0, 254, 0, 255)
if pow == nil
light.set({'bri': bri_255})
else
light.set({'bri': bri_255, 'power': pow})
end
self.update_shadow()
else
if (pow != nil) && (pow != self.shadow_onoff)
self.attribute_updated(0x0006, 0x0000)
self.shadow_onoff = pow
end
if bri_254 != self.shadow_bri
self.attribute_updated(0x0008, 0x0000)
self.shadow_bri = bri_254
end
end
end

#############################################################
# read an attribute
#
Expand Down Expand Up @@ -115,11 +153,10 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0
if cluster == 0x0008 # ========== Level Control 1.6 p.57 ==========
self.update_shadow_lazy()
if command == 0x0000 # ---------- MoveToLevel ----------
var bri_in = val.findsubval(0) # Hue 0..254
var bri = tasmota.scale_uint(bri_in, 0, 254, 0, 255)
light.set({'bri': bri})
self.update_shadow()
ctx.log = "bri:"+str(bri_in)
var bri_254 = val.findsubval(0) # Hue 0..254
self.set_bri(bri_254)
ctx.log = "bri:"+str(bri_254)
self.publish_command('Bri', bri_254, 'Dimmer', tasmota.scale_uint(bri_254, 0, 254, 0, 100))
return true
elif command == 0x0001 # ---------- Move ----------
# TODO, we don't really support it
Expand All @@ -131,12 +168,11 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0
# TODO, we don't really support it
return true
elif command == 0x0004 # ---------- MoveToLevelWithOnOff ----------
var bri_in = val.findsubval(0) # Hue 0..254
var bri = tasmota.scale_uint(bri_in, 0, 254, 0, 255)
var onoff = bri > 0
light.set({'bri': bri, 'power': onoff})
self.update_shadow()
ctx.log = "bri:"+str(bri_in)
var bri_254 = val.findsubval(0) # Hue 0..254
var onoff = bri_254 > 0
self.set_bri(bri_254, onoff)
ctx.log = "bri:"+str(bri_254)
self.publish_command('Bri', bri_254, 'Dimmer', tasmota.scale_uint(bri_254, 0, 254, 0, 100), 'Power', onoff ? 1 : 0)
return true
elif command == 0x0005 # ---------- MoveWithOnOff ----------
# TODO, we don't really support it
Expand Down
Loading