Skip to content

Commit

Permalink
Matter events phase 1 (#19484)
Browse files Browse the repository at this point in the history
  • Loading branch information
s-hadinger authored Sep 9, 2023
1 parent 4cc81f0 commit f1bd944
Show file tree
Hide file tree
Showing 28 changed files with 2,956 additions and 2,175 deletions.
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

0 comments on commit f1bd944

Please sign in to comment.