Skip to content

Commit

Permalink
Matter refactoring of bridged devices (#21575)
Browse files Browse the repository at this point in the history
  • Loading branch information
s-hadinger authored Jun 5, 2024
1 parent e198ffb commit 0bcb981
Show file tree
Hide file tree
Showing 112 changed files with 8,235 additions and 12,386 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.
### Breaking Changed

### Changed
- Matter refactoring of bridged devices

### Fixed
- Berry `input()` returns empty string and does not crash
Expand Down
36 changes: 17 additions & 19 deletions lib/libesp32/berry_matter/src/be_matter_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,11 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because
#include "solidify/solidified_Matter_Plugin_1_Root.h"
#include "solidify/solidified_Matter_Plugin_1_Aggregator.h"
#include "solidify/solidified_Matter_Plugin_1_Device.h"
#include "solidify/solidified_Matter_Plugin_2_OnOff.h"
#include "solidify/solidified_Matter_Plugin_3_OnOff.h"
#include "solidify/solidified_Matter_Plugin_9_Virt_OnOff.h"
#include "solidify/solidified_Matter_Plugin_2_Sensor_Air_Quality.h"
#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Air_Quality.h"
#include "solidify/solidified_Matter_Plugin_3_Light0.h"
#include "solidify/solidified_Matter_Plugin_2_Light0.h"
#include "solidify/solidified_Matter_Plugin_9_Virt_Light0.h"
#include "solidify/solidified_Matter_Plugin_2_Light1.h"
#include "solidify/solidified_Matter_Plugin_9_Virt_Light1.h"
Expand Down Expand Up @@ -259,22 +259,20 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because
#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Contact.h"
#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Occupancy.h"
#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Waterleak.h"
#include "solidify/solidified_Matter_Plugin_2_Bridge_HTTP.h"
#include "solidify/solidified_Matter_Plugin_4_Bridge_OnOff.h"
#include "solidify/solidified_Matter_Plugin_3_Bridge_Light0.h"
#include "solidify/solidified_Matter_Plugin_4_Bridge_Light1.h"
#include "solidify/solidified_Matter_Plugin_5_Bridge_Light2.h"
#include "solidify/solidified_Matter_Plugin_5_Bridge_Light3.h"
#include "solidify/solidified_Matter_Plugin_3_Bridge_Sensor.h"
#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Pressure.h"
#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Temp.h"
#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Illuminance.h"
#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Humidity.h"
#include "solidify/solidified_Matter_Plugin_3_Bridge_Sensor_Occupancy.h"
#include "solidify/solidified_Matter_Plugin_3_Bridge_Sensor_Contact.h"
#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Flow.h"
#include "solidify/solidified_Matter_Plugin_3_Bridge_Sensor_Air_Quality.h"
#include "solidify/solidified_Matter_Plugin_3_Bridge_Sensor_Waterleak.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_OnOff.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Light0.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Light1.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Light2.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Light3.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Pressure.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Temp.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Illuminance.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Humidity.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Occupancy.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Contact.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Flow.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Air_Quality.h"
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Waterleak.h"
#include "solidify/solidified_Matter_Plugin_z_All.h"
#include "solidify/solidified_Matter_zz_Device.h"

Expand Down Expand Up @@ -462,7 +460,7 @@ module matter (scope: global, strings: weak) {
// Plugins - only the core classes, all others are taken from `matter_device.plugins_classes`
Plugin_Root, class(be_class_Matter_Plugin_Root) // Generic behavior common to all devices
Plugin_Aggregator, class(be_class_Matter_Plugin_Aggregator) // Aggregator
Plugin_Bridge_HTTP, class(be_class_Matter_Plugin_Bridge_HTTP) // HTTP bridge superclass
Plugin_Device, class(be_class_Matter_Plugin_Device) // Device
}
@const_object_info_end */
Expand Down
77 changes: 53 additions & 24 deletions lib/libesp32/berry_matter/src/embedded/Matter_HTTP_remote.be
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ class Matter_HTTP_remote : Matter_HTTP_async
# `nil` if current request is synchronous
var reachable # is the device reachable
var reachable_utc # last tick when the reachability was seen (avoids sending superfluous ping commands)

static var STATUS_PREFIX = [
"Status", # 0
"StatusPRM", # 1
"StatusFWR", # 2
"StatusLOG", # 3
"StatusMEM", # 4
"StatusNET", # 5
"StatusMQT", # 6
"StatusTIM", # 7
nil, # 8 is deprecated and synonym of 10
"StatusPTH", # 9
"StatusSNS", # 10
"StatusSTS", # 11
"StatusSTK", # 12
"StatusSHT" # 13
]

# information gathered about the remote device (name, version...)
static var UPDATE_TIME = 5000 # update every 5s until first response
Expand All @@ -73,9 +90,9 @@ class Matter_HTTP_remote : Matter_HTTP_async
self.info = {}
if self.device
# we need different callbacks per command (don't create a single one for both calls)
self.add_schedule(self.UPDATE_CMD0, self.UPDATE_TIME, / status,payload,cmd -> self.parse_status_response(status,payload,cmd))
self.add_schedule(self.UPDATE_CMD2, self.UPDATE_TIME, / status,payload,cmd -> self.parse_status_response(status,payload,cmd))
self.add_schedule(self.UPDATE_CMD5, self.UPDATE_TIME, / status,payload,cmd -> self.parse_status_response(status,payload,cmd))
self.add_schedule(self.UPDATE_CMD0, self.UPDATE_TIME, / status,payload,cmd -> self.parse_status_response_and_call_method(status,payload,cmd,self,self.parse_status_http))
self.add_schedule(self.UPDATE_CMD2, self.UPDATE_TIME, / status,payload,cmd -> self.parse_status_response_and_call_method(status,payload,cmd,self,self.parse_status_http))
self.add_schedule(self.UPDATE_CMD5, self.UPDATE_TIME, / status,payload,cmd -> self.parse_status_response_and_call_method(status,payload,cmd,self,self.parse_status_http))
end
end

Expand All @@ -87,37 +104,49 @@ class Matter_HTTP_remote : Matter_HTTP_async

#############################################################
# parse response for `Status` and `Status 2`
def parse_status_response(status, payload, cmd)
#
# Payload can be a string (unparsed) or a map
def parse_status_response_and_call_method(status, payload, cmd, obj, method)
if status != nil && status > 0
# device is known to be reachable
self.device_is_alive(true)

import json
var j = json.load(payload)
var code = nil # index of Status
if j
# filter
if j.contains("Status") # Status 0 (actually `Status` wihtout any number)
j = j["Status"]
code = 0
elif j.contains("StatusFWR") # Status 2
j = j["StatusFWR"]
code = 2
elif j.contains("StatusNET") # Status 5
j = j["StatusNET"]
code = 5
var j = payload
if type(j) == 'string'
import json
j = json.load(j)
end
var code = nil # index of Status, nil of none
if j != nil

# detect any Status prefix and compute Status<code>
var i = 0
var prefix_tab = self.STATUS_PREFIX # move to local variable to avoid many dereferencing
while i < size(prefix_tab)
var status_prefix = prefix_tab[i]
if status_prefix != nil
if j.contains(status_prefix)
j = j[status_prefix]
code = i
break
end
end
i = i + 1
end
# convert to shadow values
self.parse_update(j, code) # call parser

# dispatch to method in charge of converting to shadow values
method(obj, j, code)
else
tasmota.log(f"MTR: *** failed to parse JSON response {payload=}", 3)
end
end
end

#############################################################
# Stub for updating shadow values (local copies of what we published to the Matter gateway)
#
# This call is synnchronous and blocking.
def parse_update(data, index)
# This call is synchronous and blocking.
def parse_status_http(data, index)
var changed = false
if index == 0 # Status
var device_name = data.find("DeviceName") # we consider 'Tasmota' as the non-information default
Expand Down Expand Up @@ -254,7 +283,7 @@ class Matter_HTTP_remote : Matter_HTTP_async

self.current_cmd = cmd
var cmd_url = "/cm?cmnd=" + string.tr(cmd, ' ', '+')
tasmota.log(format("MTR: HTTP async request 'http://%s:%i%s'", self.addr, self.port, cmd_url), 3)
tasmota.log(format("MTR: HTTP async request 'http://%s:%i%s'", self.addr, self.port, cmd_url), 4)
var ret = self.begin(cmd_url)
end

Expand All @@ -273,7 +302,7 @@ class Matter_HTTP_remote : Matter_HTTP_async

self.current_cmd = nil
var cmd_url = "/cm?cmnd=" + string.tr(cmd, ' ', '+')
tasmota.log(format("MTR: HTTP sync request 'http://%s:%i%s'", self.addr, self.port, cmd_url), 3)
tasmota.log(format("MTR: HTTP sync request 'http://%s:%i%s'", self.addr, self.port, cmd_url), 4)
var ret = super(self).begin_sync(cmd_url, timeout)
var payload_short = (ret) ? ret : 'nil'
if size(payload_short) > 30 payload_short = payload_short[0..29] + '...' end
Expand Down
5 changes: 3 additions & 2 deletions lib/libesp32/berry_matter/src/embedded/Matter_Plugin_0.be
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Matter_Plugin
# Behavior of the plugin, frequency at which `update_shadow()` is called
static var UPDATE_TIME = 5000 # default is every 5 seconds
static var VIRTUAL = false # set to true only for virtual devices
static var BRIDGE = false # set to true only for bridged devices (ESP8266 or OpenBK)
var update_next # next timestamp for update
# Configuration of the plugin: clusters and type
static var CLUSTERS = matter.consolidate_clusters(_class, {
Expand Down Expand Up @@ -143,14 +144,14 @@ class Matter_Plugin
# Returns true if it's a local device, or false for a
# remotely device controlled via HTTP
def is_local_device()
return true
return !(self.BRIDGE)
end

#############################################################
# Stub for updating shadow values (local copies of what we published to the Matter gateway)
#
# This method should collect the data from the local or remote device
# and call `parse_update(<data>)` when data is available.
# and call `parse_status(<data>)` when data is available.
#
# TO BE OVERRIDDEN
# This call is synnchronous and blocking.
Expand Down
Loading

0 comments on commit 0bcb981

Please sign in to comment.