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 refactoring of bridged devices #21575

Merged
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.
### 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