Skip to content

Commit

Permalink
read & write attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
sammachin committed Dec 27, 2024
1 parent 8fbd90f commit 2df710e
Show file tree
Hide file tree
Showing 10 changed files with 415 additions and 7 deletions.
2 changes: 0 additions & 2 deletions command.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@
<a id="refresh-sample" class="btn"><i class="fa fa-refresh"></i></a>
<pre id="sample-data"></pre>
</div>


</div>

</script>
Expand Down
28 changes: 27 additions & 1 deletion controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const os = require('os');
var { CommissioningController, NodeCommissioningOptions } = require("@project-chip/matter.js")
var { NodeStates } = require("@project-chip/matter.js/device")

const {commandOptions} = require('./utils')
const {commandOptions, attributeOptions} = require('./utils')


const environment = Environment.default;
Expand Down Expand Up @@ -143,7 +143,33 @@ module.exports = function(RED) {
}
})

// List Writable Attributes
RED.httpAdmin.get('/_mattercontroller/:cid/device/:did/cluster/:clid/attributes_writable', RED.auth.needsPermission('admin.write'), function(req,res){
let ctrl_node = RED.nodes.getNode(req.params.cid)
if (ctrl_node){
ctrl_node.commissioningController.connectNode(BigInt(req.params.did))
.then((conn) => {
let d = conn.getDevices()
atrs = d[0].getClusterClientById(Number(req.params.clid)).attributes
let response = []
Object.keys(atrs).forEach((k) => {
if (atrs[k].attribute.writable) {
response.push(k)
}
})
res.send(response)
})
}
else {
res.sendStatus(404);
}
})

// Get Attribute options
RED.httpAdmin.get('/_mattermodel/cluster/:clid/attribute/:attr/options', RED.auth.needsPermission('admin.write'), function(req,res){
let data = attributeOptions(req.params.clid, req.params.attr)
res.send(data)
})
}


4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
"nodes": {
"matter-controller": "controller.js",
"matter-manager": "manager.js",
"matter-command": "command.js"
"matter-command": "command.js",
"matter-readattr": "read_attribute.js",
"matter-writeattr": "write_attribute.js"
}
}
}
89 changes: 89 additions & 0 deletions read_attribute.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@

<script type="text/javascript">
RED.nodes.registerType('matterreadattr',{
category: 'Matter',
color: '#95cc95',
icon: "font-awesome/fa-book",
inputs:1,
outputs:1,
defaults: {
name: {value:""},
controller: { value: "", type: "mattercontroller", required: true },
device: {value:""},
deviceName: {value:""},
endpoint: {value:""},
cluster: {value:""},
attr: {value:""},
simpleMode: {value: "true"}
},
paletteLabel: "Read Attriubute",
label: function() {
let defaultName = `${this.deviceName} | ${this.attr}`
return this.name || defaultName || "Read";
},
oneditprepare: function() {
if (this.device.length != 0){
setDevice(this.controller, this.device)
}
if (this.cluster.length != 0){
setCluster(this.controller, this.device, this.cluster)
}
if (this.attr.length != 0){
setAttribute(this.controller, this.device, this.cluster, this.attr);
}
$('#refresh-devices').on("click", getDevices);
$('#refresh-clusters').on("click", getClusters);
$('#refresh-attr').on("click", getAttributes);

},
oneditsave: function() {
let el = document.getElementById('node-input-device');
this.deviceName = el.options[el.selectedIndex].innerHTML;
}
});
</script>

<script type="text/x-red" data-template-name="matterreadattr">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-controller">Controller</label>
<input type="text" id="node-input-controller" style="width:70%;">
</div>
<div class="form-row">
<label for="node-input-simpleMode">Simple Mode</label>
<input type="checkbox" id="node-input-simpleMode" value="true" >
</div>
<div class="form-row">
<label for="node-input-device">Device</label>
<select type="text" id="node-input-device" style="width:50%;" >
</select>
<a id="refresh-devices" class="btn"><i class="fa fa-refresh"></i></a>
</div>
<!--
<div class="form-row">
<label for="node-input-endpoint">Endpoint</label>
<select type="text" id="node-input-endpoint" style="width:50%;" >
</select>
</div>
-->
<div class="form-row">
<label for="node-input-cluster">Cluster</label>
<select type="text" id="node-input-cluster" style="width:50%;" >
</select>
<a id="refresh-clusters" class="btn"><i class="fa fa-refresh"></i></a>
</div>
<div class="form-row">
<label for="node-input-attr">Attribute</label>
<select type="text" id="node-input-attr" style="width:50%;" >
</select>
<a id="refresh-attr" class="btn"><i class="fa fa-refresh"></i></a>
</div>
</script>

<script type="text/x-red" data-help-name="matterreadattr">
<p>Read an Attribute on a Device</p>
</script>

35 changes: 35 additions & 0 deletions read_attribute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const {cap} = require('./utils')



module.exports = function(RED) {
function MatterReadAttr(config) {
RED.nodes.createNode(this, config);
var node = this;
node.controller = RED.nodes.getNode(config.controller);
node.device = BigInt(config.device)
node.endpoint = config.endpoint || 0
node.cluster = Number(config.cluster)
node.attr = cap(config.attr)
this.on('input', function(msg) {
node.controller.commissioningController.connectNode(node.device).then((device) => {
const ep = device.getDevices()
const clc = ep[Number(node.endpoint)].getClusterClientById(Number(node.cluster))
try {
let command = eval(`clc.get${node.attr}Attribute`)
command()
.then((attr_resp) => {
msg.payload = attr_resp
node.send(msg)
})
.catch((e) => node.error(e))
} catch (error) {
node.error(error)
}
})
})
}

RED.nodes.registerType("matterreadattr",MatterReadAttr);

}
2 changes: 1 addition & 1 deletion repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var { NodeStates } = await import("@project-chip/matter.js/device")
const logger = Logger.get("Controller");
const environment = Environment.default;

Logger.defaultLogLevel = 0;
Logger.defaultLogLevel = 4;

const commissioningController = new CommissioningController({
environment: {
Expand Down
101 changes: 100 additions & 1 deletion resources/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ const simpleCommands = {
'8' : ["moveToLevel"],
'768' : ["moveToHue", "moveToSaturation", "moveToColorTemperature"]
}
const simpleAtrributes = []
const simpleAttributes = {
'3' : ["identifyTime"],
'6' : ["onOff", "onTime", "offWaitTime", "startUpOnOff"],
'8' : ["currentLevel", "maxLevel", "minLevel", ],
'768' : ["currentMode", "currentHue", "currentSaturation", "colorTemperatureMireds"]
}

function getDevices() {
//console.log('getDevices')
Expand Down Expand Up @@ -203,6 +208,86 @@ function setCommand(ctrl_node, device, cluster, command){

}

function getAttributes(writable=false){
console.log('getAttributes')
ctrl_node = document.getElementById('node-input-controller').value
device = document.getElementById('node-input-device').value
cluster = document.getElementById('node-input-cluster').value
let simpleMode = document.getElementById("node-input-simpleMode")
if ((ctrl_node != '_ADD_' || ctrl_node != undefined) && (device != undefined || device != '__SELECT__') && (cluster != undefined || cluster != '__SELECT__')){
if (writable){
url =`_mattercontroller/${ctrl_node}/device/${device}/cluster/${cluster}/attributes_writable`
} else{
url =`_mattercontroller/${ctrl_node}/device/${device}/cluster/${cluster}/attributes`
}
$.get(url, function(r) {
var attrs = document.getElementById("node-input-attr");
removeOptions(attrs)
var option = document.createElement("option");
option.text = '--SELECT--'
option.value = undefined
attrs.add(option)
r.forEach(d => {
if (simpleMode.checked){
if (simpleAttributes[cluster].includes(d)) {
var option = document.createElement("option");
option.text = d
option.value = d
option.id = d
attrs.add(option);
}
} else {
var option = document.createElement("option");
option.text = d
option.value = d
option.id = d
attrs.add(option);
}
});
})
}
}
function setAttribute(ctrl_node, device, cluster, attr, writable=false){
console.log(`setAttribute , ${ctrl_node}, ${device}, ${cluster}, ${attr}`)
let simpleMode = document.getElementById("node-input-simpleMode")
if ((ctrl_node != '_ADD_' || ctrl_node != undefined) || (device != undefined || device != '__SELECT__') && (cluster != undefined || cluster != '__SELECT__')){
if (writable){
url =`_mattercontroller/${ctrl_node}/device/${device}/cluster/${cluster}/attributes_writable`
} else{
url =`_mattercontroller/${ctrl_node}/device/${device}/cluster/${cluster}/attributes`
}
$.get(url, function(r) {
var attrs = document.getElementById("node-input-attr");
removeOptions(attrs)
var option = document.createElement("option");
option.text = '--SELECT--'
option.value = undefined
attrs.add(option)
r.forEach(d => {
if (simpleMode.checked){
if (simpleAttributes[cluster].includes(d)) {
var option = document.createElement("option");
option.text = d
option.value = d
option.id = d
if (attr == d) { option.selected=true}
attrs.add(option);
}
} else {
var option = document.createElement("option");
option.text = d
option.value = d
option.id = d
if (attr == d) { option.selected=true}
attrs.add(option);
}
});
})
}

}


function getCommandOpts(){
let clusterID = document.getElementById("node-input-cluster").value
let command = document.getElementById("node-input-command").value
Expand All @@ -212,6 +297,20 @@ function getCommandOpts(){
})
}

function getAttributeOpts(){
console.log(`getAttributeOpts`)
let clusterID = document.getElementById("node-input-cluster").value
let attribute = document.getElementById("node-input-attr").value
url = `_mattermodel/cluster/${clusterID}/attribute/${attribute}/options`
$.get(url, function(r) {
let details = r.details
delete(r.details)
document.getElementById('sample-data').innerHTML=JSON.stringify(r, null, 2)
document.getElementById('sample-details').innerHTML=details
})
}


function removeOptions(selectElement) {
var i, L = selectElement.options.length - 1;
for(i = L; i >= 0; i--) {
Expand Down
18 changes: 17 additions & 1 deletion utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,20 @@ function commandOptions(clusterID, commandName){
return data
}

module.exports = {commandOptions}
function attributeOptions(clusterID, attributeName){
data = {}
clusterName = Models.MatterModel.standard.get(Models.ClusterModel, Number(clusterID)).name
cluster = eval('Models.'+clusterName)
cluster.attributes.forEach((attr, i) => {
if (attr.name == cap(attributeName)){
data.name = attr.name
data.defaut = attr.default || ''
data.constraint = attr.constraint || ''
data.type = attr.type
data.details = attr.details || ''
}
})
return data
}

module.exports = {commandOptions, attributeOptions, deCap, cap}
Loading

0 comments on commit 2df710e

Please sign in to comment.