@project-chip/matter-node.js-examples 0.8.0 → 0.8.1-alpha.0-20240403-811441fb

Sign up to get free protection for your applications and to get access to all the features.
@@ -74,15 +74,11 @@ for (let idx = 0; idx < isSocket.length; idx++) {
74
74
  }
75
75
  );
76
76
  await aggregator.add(endpoint);
77
- let isIdentifying = false;
78
- endpoint.events.identify.identifyTime$Change.on((value) => {
79
- if (value > 0 && !isIdentifying) {
80
- isIdentifying = true;
81
- console.log(`${name}: Run identify logic, ideally blink a light every 0.5s ...`);
82
- } else if (value === 0) {
83
- isIdentifying = false;
84
- console.log(`${name}: Stop identify logic ...`);
85
- }
77
+ endpoint.events.identify.startIdentifying.on(() => {
78
+ console.log(`Run identify logic for ${name}, ideally blink a light every 0.5s ...`);
79
+ });
80
+ endpoint.events.identify.stopIdentifying.on(() => {
81
+ console.log(`Stop identify logic for ${name} ...`);
86
82
  });
87
83
  endpoint.events.onOff.onOff$Change.on((value) => {
88
84
  executeCommand(value ? `on${i}` : `off${i}`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/examples/BridgedDevicesNode.ts"],
4
- "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example shows how to create a new device node that is composed of multiple devices.\n * It creates multiple endpoints on the server. For information on how to add a composed device to a bridge please\n * refer to the bridge example!\n * It can be used as CLI script and starting point for your own device node implementation.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { BridgedDeviceBasicInformationServer } from \"@project-chip/matter.js/behavior/definitions/bridged-device-basic-information\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { AggregatorEndpoint } from \"@project-chip/matter.js/endpoint/definitions\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { execSync } from \"child_process\";\n\nrequireMinNodeVersion(16);\n\n/** Initialize configuration values */\nconst { isSocket, deviceName, vendorName, passcode, discriminator, vendorId, productName, productId, port, uniqueId } =\n await getConfiguration();\n\n/**\n * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration\n */\nconst server = await ServerNode.create({\n // Required: Give the Node a unique ID which is used to store the state of this node\n id: uniqueId,\n\n // Provide Network relevant configuration like the port\n // Optional when operating only one device on a host, Default port is 5540\n network: {\n port,\n },\n\n // Provide Commissioning relevant settings\n // Optional for development/testing purposes\n commissioning: {\n passcode,\n discriminator,\n },\n\n // Provide Node announcement settings\n // Optional: If Ommitted some development defaults are used\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(isSocket[0] ? OnOffPlugInUnitDevice.deviceType : OnOffLightDevice.deviceType),\n },\n\n // Provide defaults for the BasicInformation cluster on the Root endpoint\n // Optional: If Omitted some development defaults are used\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `matterjs-${uniqueId}`,\n uniqueId,\n },\n});\n\n/**\n * Matter Nodes are a composition of endpoints. Create and add a single multiple endpoint to the node to make it a\n * composed device. This example uses the OnOffLightDevice or OnOffPlugInUnitDevice depending on the value of the type\n * parameter. It also assigns each Endpoint a unique ID to store the endpoint number for it in the storage to restore\n * the device on restart.\n *\n * In this case we directly use the default command implementation from matter.js. Check out the DeviceNodeFull example\n * to see how to customize the command handlers.\n */\n\nconst aggregator = new Endpoint(AggregatorEndpoint, { id: \"aggregator\" });\nawait server.add(aggregator);\n\nfor (let idx = 0; idx < isSocket.length; idx++) {\n const i = idx + 1;\n const isASocket = isSocket[idx]; // Is the Device we add a Socket or a Light?\n\n const name = `OnOff ${isASocket ? \"Socket\" : \"Light\"} ${i}`;\n\n const endpoint = new Endpoint(\n isASocket\n ? // For a Bridged Device we need to add a BridgedDeviceBasicInformation cluster as server\n OnOffPlugInUnitDevice.with(BridgedDeviceBasicInformationServer)\n : OnOffLightDevice.with(BridgedDeviceBasicInformationServer),\n {\n id: `onoff-${i}`,\n bridgedDeviceBasicInformation: {\n nodeLabel: name,\n productName: name,\n productLabel: name,\n serialNumber: `node-matter-${uniqueId}-${i}`,\n reachable: true,\n },\n },\n );\n await aggregator.add(endpoint);\n\n /**\n * Register state change handlers of the endpoint for identify and onoff states to react to the commands.\n *\n * If the code in these change handlers fail then the change is also rolled back and not executed and an error is\n * reported back to the controller.\n */\n let isIdentifying = false;\n endpoint.events.identify.identifyTime$Change.on(value => {\n // identifyTime is set when an identify commandf is called and then decreased every second while indenitfy logic runs.\n if (value > 0 && !isIdentifying) {\n isIdentifying = true;\n console.log(`${name}: Run identify logic, ideally blink a light every 0.5s ...`);\n } else if (value === 0) {\n isIdentifying = false;\n console.log(`${name}: Stop identify logic ...`);\n }\n });\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? `on${i}` : `off${i}`);\n console.log(`${name} is now ${value ? \"ON\" : \"OFF\"}`);\n });\n}\n\n/**\n * In order to start the node and announce it into the network we use the run method which resolves when the node goes\n * offline again because we do not need anything more here. See the Full example for other starting options.\n * The QR Code is printed automatically.\n */\nawait server.bringOnline();\n\n/**\n * Log the endpoint structure for debugging reasons and to allow to verify anything is correct\n */\nlogEndpoint(EndpointServer.forEndpoint(server));\n\n/*\n If you want to dynamically add another device during runtime you can do so by doing the following:\n\n const name = `OnOff Light 3`;\n\n const endpoint = new Endpoint(OnOffLightDevice.with(BridgedDeviceBasicInformationServer), {\n id: `onoff-3`,\n bridgedDeviceBasicInformation: {\n nodeLabel: name,\n productName: name,\n productLabel: name,\n serialNumber: `node-matter-${uniqueId}-3`,\n reachable: true,\n },\n });\n await aggregator.add(endpoint);\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? `on3` : `off3`);\n console.log(`${name} is now ${value ? \"ON\" : \"OFF\"}`);\n });\n\n */\n\n/*\n To remove a device during runtime you can do so by doing the following:\n console.log(\"Removing Light 3 now!!\");\n\n await endpoint.close();\n\n This will automatically remove the endpoint from the bridge.\n */\n\n/*********************************************************************************************************\n * Convenience Methods\n *********************************************************************************************************/\n\n/** Defined a shell command from an environment variable and execute it and log the response. */\nfunction executeCommand(scriptParamName: string) {\n const script = Environment.default.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\nasync function getConfiguration() {\n /**\n * Collect all needed data\n *\n * This block collects all needed data from cli, environment or storage. Replace this with where ever your data come from.\n *\n * Note: This example uses the matter.js process storage system to store the device parameter data for convenience\n * and easy reuse. When you also do that be careful to not overlap with Matter-Server own storage contexts\n * (so maybe better not do it ;-)).\n */\n const environment = Environment.default;\n\n const storageService = environment.get(StorageService);\n console.log(`Storage location: ${storageService.location} (Directory)`);\n console.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n );\n const deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\n const isSocket = Array<boolean>();\n const numDevices = environment.vars.number(\"num\") || 2;\n if (await deviceStorage.has(\"isSocket\")) {\n console.log(`Device types found in storage. --type parameter is ignored.`);\n (await deviceStorage.get<Array<boolean>>(\"isSocket\")).forEach(type => isSocket.push(type));\n }\n for (let i = 1; i <= numDevices; i++) {\n if (isSocket[i - 1] !== undefined) continue;\n isSocket.push(environment.vars.string(`type${i}`) === \"socket\");\n }\n\n const deviceName = \"Matter test device\";\n const vendorName = \"matter-node.js\";\n const passcode = environment.vars.number(\"passcode\") ?? (await deviceStorage.get(\"passcode\", 20202021));\n const discriminator = environment.vars.number(\"discriminator\") ?? (await deviceStorage.get(\"discriminator\", 3840));\n // product name / id and vendor id should match what is in the device certificate\n const vendorId = environment.vars.number(\"vendorid\") ?? (await deviceStorage.get(\"vendorid\", 0xfff1));\n const productName = `node-matter OnOff ${isSocket ? \"Socket\" : \"Light\"}`;\n const productId = environment.vars.number(\"productid\") ?? (await deviceStorage.get(\"productid\", 0x8000));\n\n const port = environment.vars.number(\"port\") ?? 5540;\n\n const uniqueId =\n environment.vars.string(\"uniqueid\") ?? (await deviceStorage.get(\"uniqueid\", Time.nowMs().toString()));\n\n // Persist basic data to keep them also on restart\n await deviceStorage.set({\n passcode,\n discriminator,\n vendorid: vendorId,\n productid: productId,\n isSocket,\n uniqueid: uniqueId,\n });\n\n return {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example shows how to create a new device node that is composed of multiple devices.\n * It creates multiple endpoints on the server. For information on how to add a composed device to a bridge please\n * refer to the bridge example!\n * It can be used as CLI script and starting point for your own device node implementation.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { BridgedDeviceBasicInformationServer } from \"@project-chip/matter.js/behavior/definitions/bridged-device-basic-information\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { AggregatorEndpoint } from \"@project-chip/matter.js/endpoint/definitions\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { execSync } from \"child_process\";\n\nrequireMinNodeVersion(16);\n\n/** Initialize configuration values */\nconst { isSocket, deviceName, vendorName, passcode, discriminator, vendorId, productName, productId, port, uniqueId } =\n await getConfiguration();\n\n/**\n * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration\n */\nconst server = await ServerNode.create({\n // Required: Give the Node a unique ID which is used to store the state of this node\n id: uniqueId,\n\n // Provide Network relevant configuration like the port\n // Optional when operating only one device on a host, Default port is 5540\n network: {\n port,\n },\n\n // Provide Commissioning relevant settings\n // Optional for development/testing purposes\n commissioning: {\n passcode,\n discriminator,\n },\n\n // Provide Node announcement settings\n // Optional: If Ommitted some development defaults are used\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(isSocket[0] ? OnOffPlugInUnitDevice.deviceType : OnOffLightDevice.deviceType),\n },\n\n // Provide defaults for the BasicInformation cluster on the Root endpoint\n // Optional: If Omitted some development defaults are used\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `matterjs-${uniqueId}`,\n uniqueId,\n },\n});\n\n/**\n * Matter Nodes are a composition of endpoints. Create and add a single multiple endpoint to the node to make it a\n * composed device. This example uses the OnOffLightDevice or OnOffPlugInUnitDevice depending on the value of the type\n * parameter. It also assigns each Endpoint a unique ID to store the endpoint number for it in the storage to restore\n * the device on restart.\n *\n * In this case we directly use the default command implementation from matter.js. Check out the DeviceNodeFull example\n * to see how to customize the command handlers.\n */\n\nconst aggregator = new Endpoint(AggregatorEndpoint, { id: \"aggregator\" });\nawait server.add(aggregator);\n\nfor (let idx = 0; idx < isSocket.length; idx++) {\n const i = idx + 1;\n const isASocket = isSocket[idx]; // Is the Device we add a Socket or a Light?\n\n const name = `OnOff ${isASocket ? \"Socket\" : \"Light\"} ${i}`;\n\n const endpoint = new Endpoint(\n isASocket\n ? // For a Bridged Device we need to add a BridgedDeviceBasicInformation cluster as server\n OnOffPlugInUnitDevice.with(BridgedDeviceBasicInformationServer)\n : OnOffLightDevice.with(BridgedDeviceBasicInformationServer),\n {\n id: `onoff-${i}`,\n bridgedDeviceBasicInformation: {\n nodeLabel: name,\n productName: name,\n productLabel: name,\n serialNumber: `node-matter-${uniqueId}-${i}`,\n reachable: true,\n },\n },\n );\n await aggregator.add(endpoint);\n\n /**\n * Register state change handlers and events of the endpoint for identify and onoff states to react to the commands.\n *\n * If the code in these change handlers fail then the change is also rolled back and not executed and an error is\n * reported back to the controller.\n */\n endpoint.events.identify.startIdentifying.on(() => {\n console.log(`Run identify logic for ${name}, ideally blink a light every 0.5s ...`);\n });\n\n endpoint.events.identify.stopIdentifying.on(() => {\n console.log(`Stop identify logic for ${name} ...`);\n });\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? `on${i}` : `off${i}`);\n console.log(`${name} is now ${value ? \"ON\" : \"OFF\"}`);\n });\n}\n\n/**\n * In order to start the node and announce it into the network we use the run method which resolves when the node goes\n * offline again because we do not need anything more here. See the Full example for other starting options.\n * The QR Code is printed automatically.\n */\nawait server.bringOnline();\n\n/**\n * Log the endpoint structure for debugging reasons and to allow to verify anything is correct\n */\nlogEndpoint(EndpointServer.forEndpoint(server));\n\n/*\n If you want to dynamically add another device during runtime you can do so by doing the following:\n\n const name = `OnOff Light 3`;\n\n const endpoint = new Endpoint(OnOffLightDevice.with(BridgedDeviceBasicInformationServer), {\n id: `onoff-3`,\n bridgedDeviceBasicInformation: {\n nodeLabel: name,\n productName: name,\n productLabel: name,\n serialNumber: `node-matter-${uniqueId}-3`,\n reachable: true,\n },\n });\n await aggregator.add(endpoint);\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? `on3` : `off3`);\n console.log(`${name} is now ${value ? \"ON\" : \"OFF\"}`);\n });\n\n */\n\n/*\n To remove a device during runtime you can do so by doing the following:\n console.log(\"Removing Light 3 now!!\");\n\n await endpoint.close();\n\n This will automatically remove the endpoint from the bridge.\n */\n\n/*********************************************************************************************************\n * Convenience Methods\n *********************************************************************************************************/\n\n/** Defined a shell command from an environment variable and execute it and log the response. */\nfunction executeCommand(scriptParamName: string) {\n const script = Environment.default.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\nasync function getConfiguration() {\n /**\n * Collect all needed data\n *\n * This block collects all needed data from cli, environment or storage. Replace this with where ever your data come from.\n *\n * Note: This example uses the matter.js process storage system to store the device parameter data for convenience\n * and easy reuse. When you also do that be careful to not overlap with Matter-Server own storage contexts\n * (so maybe better not do it ;-)).\n */\n const environment = Environment.default;\n\n const storageService = environment.get(StorageService);\n console.log(`Storage location: ${storageService.location} (Directory)`);\n console.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n );\n const deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\n const isSocket = Array<boolean>();\n const numDevices = environment.vars.number(\"num\") || 2;\n if (await deviceStorage.has(\"isSocket\")) {\n console.log(`Device types found in storage. --type parameter is ignored.`);\n (await deviceStorage.get<Array<boolean>>(\"isSocket\")).forEach(type => isSocket.push(type));\n }\n for (let i = 1; i <= numDevices; i++) {\n if (isSocket[i - 1] !== undefined) continue;\n isSocket.push(environment.vars.string(`type${i}`) === \"socket\");\n }\n\n const deviceName = \"Matter test device\";\n const vendorName = \"matter-node.js\";\n const passcode = environment.vars.number(\"passcode\") ?? (await deviceStorage.get(\"passcode\", 20202021));\n const discriminator = environment.vars.number(\"discriminator\") ?? (await deviceStorage.get(\"discriminator\", 3840));\n // product name / id and vendor id should match what is in the device certificate\n const vendorId = environment.vars.number(\"vendorid\") ?? (await deviceStorage.get(\"vendorid\", 0xfff1));\n const productName = `node-matter OnOff ${isSocket ? \"Socket\" : \"Light\"}`;\n const productId = environment.vars.number(\"productid\") ?? (await deviceStorage.get(\"productid\", 0x8000));\n\n const port = environment.vars.number(\"port\") ?? 5540;\n\n const uniqueId =\n environment.vars.string(\"uniqueid\") ?? (await deviceStorage.get(\"uniqueid\", Time.nowMs().toString()));\n\n // Persist basic data to keep them also on restart\n await deviceStorage.set({\n passcode,\n discriminator,\n vendorid: vendorId,\n productid: productId,\n isSocket,\n uniqueid: uniqueId,\n });\n\n return {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["isSocket", "deviceName", "vendorName", "passcode", "discriminator", "vendorId", "productName", "productId", "port", "uniqueId"]
7
7
  }
@@ -54,15 +54,11 @@ for (let idx = 0; idx < isSocket.length; idx++) {
54
54
  const isASocket = isSocket[idx];
55
55
  const endpoint = new Endpoint(isASocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: `onoff-${i}` });
56
56
  await server.add(endpoint);
57
- let isIdentifying = false;
58
- endpoint.events.identify.identifyTime$Change.on((value) => {
59
- if (value > 0 && !isIdentifying) {
60
- isIdentifying = true;
61
- console.log(`OnOff ${i}: Run identify logic, ideally blink a light every 0.5s ...`);
62
- } else if (value === 0) {
63
- isIdentifying = false;
64
- console.log(`OnOff ${i}: Stop identify logic ...`);
65
- }
57
+ endpoint.events.identify.startIdentifying.on(() => {
58
+ console.log(`Run identify logic for sub device ${i}, ideally blink a light every 0.5s ...`);
59
+ });
60
+ endpoint.events.identify.stopIdentifying.on(() => {
61
+ console.log(`Stop identify logic for sub device ${i}...`);
66
62
  });
67
63
  endpoint.events.onOff.onOff$Change.on((value) => {
68
64
  executeCommand(value ? `on${i}` : `off${i}`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/examples/ComposedDeviceNode.ts"],
4
- "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example shows how to create a new device node that is composed of multiple devices.\n * It creates multiple endpoints on the server. For information on how to add a composed device to a bridge please\n * refer to the bridge example!\n * It can be used as CLI script and starting point for your own device node implementation.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { execSync } from \"child_process\";\n\nrequireMinNodeVersion(16);\n\n/** Initialize configuration values */\nconst { isSocket, deviceName, vendorName, passcode, discriminator, vendorId, productName, productId, port, uniqueId } =\n await getConfiguration();\n\n/**\n * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration\n */\nconst server = await ServerNode.create({\n // Required: Give the Node a unique ID which is used to store the state of this node\n id: uniqueId,\n\n // Provide Network relevant configuration like the port\n // Optional when operating only one device on a host, Default port is 5540\n network: {\n port,\n },\n\n // Provide Commissioning relevant settings\n // Optional for development/testing purposes\n commissioning: {\n passcode,\n discriminator,\n },\n\n // Provide Node announcement settings\n // Optional: If Ommitted some development defaults are used\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(isSocket[0] ? OnOffPlugInUnitDevice.deviceType : OnOffLightDevice.deviceType),\n },\n\n // Provide defaults for the BasicInformation cluster on the Root endpoint\n // Optional: If Omitted some development defaults are used\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `matterjs-${uniqueId}`,\n uniqueId,\n },\n});\n\n/**\n * Matter Nodes are a composition of endpoints. Create and add a single multiple endpoint to the node to make it a\n * composed device. This example uses the OnOffLightDevice or OnOffPlugInUnitDevice depending on the value of the type\n * parameter. It also assigns each Endpoint a unique ID to store the endpoint number for it in the storage to restore\n * the device on restart.\n *\n * In this case we directly use the default command implementation from matter.js. Check out the DeviceNodeFull example\n * to see how to customize the command handlers.\n */\n\nfor (let idx = 0; idx < isSocket.length; idx++) {\n const i = idx + 1;\n const isASocket = isSocket[idx]; // Is the Device we add a Socket or a Light?\n const endpoint = new Endpoint(isASocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: `onoff-${i}` });\n await server.add(endpoint);\n\n /**\n * Register state change handlers of the endpoint for identify and onoff states to react to the commands.\n *\n * If the code in these change handlers fail then the change is also rolled back and not executed and an error is\n * reported back to the controller.\n */\n let isIdentifying = false;\n endpoint.events.identify.identifyTime$Change.on(value => {\n // identifyTime is set when an identify command is called and then decreased every second while indentify logic runs.\n if (value > 0 && !isIdentifying) {\n isIdentifying = true;\n console.log(`OnOff ${i}: Run identify logic, ideally blink a light every 0.5s ...`);\n } else if (value === 0) {\n isIdentifying = false;\n console.log(`OnOff ${i}: Stop identify logic ...`);\n }\n });\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? `on${i}` : `off${i}`);\n console.log(`OnOff ${i} is now ${value ? \"ON\" : \"OFF\"}`);\n });\n}\n\n/**\n * Log the endpoint structure for debugging reasons and to allow to verify anything is correct\n */\nlogEndpoint(EndpointServer.forEndpoint(server));\n\n/**\n * In order to start the node and announce it into the network we use the run method which resolves when the node goes\n * offline again because we do not need anything more here. See the Full example for other starting options.\n * The QR Code is printed automatically.\n */\nawait server.run();\n\n/*********************************************************************************************************\n * Convenience Methods\n *********************************************************************************************************/\n\n/**\n * Defines a shell command from an environment variable and execute it and log the response\n */\nfunction executeCommand(scriptParamName: string) {\n const script = Environment.default.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\nasync function getConfiguration() {\n const environment = Environment.default;\n\n const storageService = environment.get(StorageService);\n console.log(`Storage location: ${storageService.location} (Directory)`);\n console.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n );\n const deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\n const isSocket = Array<boolean>();\n const numDevices = environment.vars.number(\"num\") || 2;\n if (await deviceStorage.has(\"isSocket\")) {\n console.log(`Device types found in storage. --type parameter is ignored.`);\n (await deviceStorage.get<Array<boolean>>(\"isSocket\")).forEach(type => isSocket.push(type));\n }\n for (let i = 1; i < numDevices; i++) {\n if (isSocket[i - 1] !== undefined) continue;\n isSocket.push(environment.vars.string(`type${i}`) === \"socket\");\n }\n\n const deviceName = \"Matter test device\";\n const vendorName = \"matter-node.js\";\n const passcode = environment.vars.number(\"passcode\") ?? (await deviceStorage.get(\"passcode\", 20202021));\n const discriminator = environment.vars.number(\"discriminator\") ?? (await deviceStorage.get(\"discriminator\", 3840));\n // product name / id and vendor id should match what is in the device certificate\n const vendorId = environment.vars.number(\"vendorid\") ?? (await deviceStorage.get(\"vendorid\", 0xfff1));\n const productName = `node-matter OnOff ${isSocket ? \"Socket\" : \"Light\"}`;\n const productId = environment.vars.number(\"productid\") ?? (await deviceStorage.get(\"productid\", 0x8000));\n\n const port = environment.vars.number(\"port\") ?? 5540;\n\n const uniqueId =\n environment.vars.string(\"uniqueid\") ?? (await deviceStorage.get(\"uniqueid\", Time.nowMs().toString()));\n\n // Persist basic data to keep them also on restart\n await deviceStorage.set({\n passcode,\n discriminator,\n vendorid: vendorId,\n productid: productId,\n isSocket,\n uniqueid: uniqueId,\n });\n\n return {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example shows how to create a new device node that is composed of multiple devices.\n * It creates multiple endpoints on the server. For information on how to add a composed device to a bridge please\n * refer to the bridge example!\n * It can be used as CLI script and starting point for your own device node implementation.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { execSync } from \"child_process\";\n\nrequireMinNodeVersion(16);\n\n/** Initialize configuration values */\nconst { isSocket, deviceName, vendorName, passcode, discriminator, vendorId, productName, productId, port, uniqueId } =\n await getConfiguration();\n\n/**\n * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration\n */\nconst server = await ServerNode.create({\n // Required: Give the Node a unique ID which is used to store the state of this node\n id: uniqueId,\n\n // Provide Network relevant configuration like the port\n // Optional when operating only one device on a host, Default port is 5540\n network: {\n port,\n },\n\n // Provide Commissioning relevant settings\n // Optional for development/testing purposes\n commissioning: {\n passcode,\n discriminator,\n },\n\n // Provide Node announcement settings\n // Optional: If Ommitted some development defaults are used\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(isSocket[0] ? OnOffPlugInUnitDevice.deviceType : OnOffLightDevice.deviceType),\n },\n\n // Provide defaults for the BasicInformation cluster on the Root endpoint\n // Optional: If Omitted some development defaults are used\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `matterjs-${uniqueId}`,\n uniqueId,\n },\n});\n\n/**\n * Matter Nodes are a composition of endpoints. Create and add a single multiple endpoint to the node to make it a\n * composed device. This example uses the OnOffLightDevice or OnOffPlugInUnitDevice depending on the value of the type\n * parameter. It also assigns each Endpoint a unique ID to store the endpoint number for it in the storage to restore\n * the device on restart.\n *\n * In this case we directly use the default command implementation from matter.js. Check out the DeviceNodeFull example\n * to see how to customize the command handlers.\n */\n\nfor (let idx = 0; idx < isSocket.length; idx++) {\n const i = idx + 1;\n const isASocket = isSocket[idx]; // Is the Device we add a Socket or a Light?\n const endpoint = new Endpoint(isASocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: `onoff-${i}` });\n await server.add(endpoint);\n\n /**\n * Register state change handlers of the endpoint for identify and onoff states to react to the commands.\n *\n * If the code in these change handlers fail then the change is also rolled back and not executed and an error is\n * reported back to the controller.\n */\n endpoint.events.identify.startIdentifying.on(() => {\n console.log(`Run identify logic for sub device ${i}, ideally blink a light every 0.5s ...`);\n });\n\n endpoint.events.identify.stopIdentifying.on(() => {\n console.log(`Stop identify logic for sub device ${i}...`);\n });\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? `on${i}` : `off${i}`);\n console.log(`OnOff ${i} is now ${value ? \"ON\" : \"OFF\"}`);\n });\n}\n\n/**\n * Log the endpoint structure for debugging reasons and to allow to verify anything is correct\n */\nlogEndpoint(EndpointServer.forEndpoint(server));\n\n/**\n * In order to start the node and announce it into the network we use the run method which resolves when the node goes\n * offline again because we do not need anything more here. See the Full example for other starting options.\n * The QR Code is printed automatically.\n */\nawait server.run();\n\n/*********************************************************************************************************\n * Convenience Methods\n *********************************************************************************************************/\n\n/**\n * Defines a shell command from an environment variable and execute it and log the response\n */\nfunction executeCommand(scriptParamName: string) {\n const script = Environment.default.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\nasync function getConfiguration() {\n const environment = Environment.default;\n\n const storageService = environment.get(StorageService);\n console.log(`Storage location: ${storageService.location} (Directory)`);\n console.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n );\n const deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\n const isSocket = Array<boolean>();\n const numDevices = environment.vars.number(\"num\") || 2;\n if (await deviceStorage.has(\"isSocket\")) {\n console.log(`Device types found in storage. --type parameter is ignored.`);\n (await deviceStorage.get<Array<boolean>>(\"isSocket\")).forEach(type => isSocket.push(type));\n }\n for (let i = 1; i < numDevices; i++) {\n if (isSocket[i - 1] !== undefined) continue;\n isSocket.push(environment.vars.string(`type${i}`) === \"socket\");\n }\n\n const deviceName = \"Matter test device\";\n const vendorName = \"matter-node.js\";\n const passcode = environment.vars.number(\"passcode\") ?? (await deviceStorage.get(\"passcode\", 20202021));\n const discriminator = environment.vars.number(\"discriminator\") ?? (await deviceStorage.get(\"discriminator\", 3840));\n // product name / id and vendor id should match what is in the device certificate\n const vendorId = environment.vars.number(\"vendorid\") ?? (await deviceStorage.get(\"vendorid\", 0xfff1));\n const productName = `node-matter OnOff ${isSocket ? \"Socket\" : \"Light\"}`;\n const productId = environment.vars.number(\"productid\") ?? (await deviceStorage.get(\"productid\", 0x8000));\n\n const port = environment.vars.number(\"port\") ?? 5540;\n\n const uniqueId =\n environment.vars.string(\"uniqueid\") ?? (await deviceStorage.get(\"uniqueid\", Time.nowMs().toString()));\n\n // Persist basic data to keep them also on restart\n await deviceStorage.set({\n passcode,\n discriminator,\n vendorid: vendorId,\n productid: productId,\n isSocket,\n uniqueid: uniqueId,\n });\n\n return {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["isSocket", "deviceName", "vendorName", "passcode", "discriminator", "vendorId", "productName", "productId", "port", "uniqueId"]
7
7
  }
@@ -63,15 +63,11 @@ async function main() {
63
63
  });
64
64
  const endpoint = new Endpoint(isSocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: "onoff" });
65
65
  await server.add(endpoint);
66
- let isIdentifying = false;
67
- endpoint.events.identify.identifyTime$Change.on((value) => {
68
- if (value > 0 && !isIdentifying) {
69
- isIdentifying = true;
70
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
71
- } else if (value === 0) {
72
- isIdentifying = false;
73
- console.log(`Stop identify logic ...`);
74
- }
66
+ endpoint.events.identify.startIdentifying.on(() => {
67
+ console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
68
+ });
69
+ endpoint.events.identify.stopIdentifying.on(() => {
70
+ console.log(`Stop identify logic ...`);
75
71
  });
76
72
  endpoint.events.onOff.onOff$Change.on((value) => {
77
73
  executeCommand(value ? "on" : "off");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/examples/DeviceNode.ts"],
4
- "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example shows how to create a simple on-off Matter device as a light or as a socket.\n * It can be used as CLI script and starting point for your own device node implementation.\n * This example is CJS conform and do not use top level await's.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { execSync } from \"child_process\";\n\nrequireMinNodeVersion(16);\n\nasync function main() {\n /** Initialize configuration values */\n const {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n } = await getConfiguration();\n\n /**\n * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration\n */\n const server = await ServerNode.create({\n // Required: Give the Node a unique ID which is used to store the state of this node\n id: uniqueId,\n\n // Provide Network relevant configuration like the port\n // Optional when operating only one device on a host, Default port is 5540\n network: {\n port,\n },\n\n // Provide Commissioning relevant settings\n // Optional for development/testing purposes\n commissioning: {\n passcode,\n discriminator,\n },\n\n // Provide Node announcement settings\n // Optional: If Ommitted some development defaults are used\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(isSocket ? OnOffPlugInUnitDevice.deviceType : OnOffLightDevice.deviceType),\n },\n\n // Provide defaults for the BasicInformation cluster on the Root endpoint\n // Optional: If Omitted some development defaults are used\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `matterjs-${uniqueId}`,\n uniqueId,\n },\n });\n\n /**\n * Matter Nodes are a composition of endpoints. Create and add a single endpoint to the node. This example uses the\n * OnOffLightDevice or OnOffPlugInUnitDevice depending on the value of the type parameter. It also assigns this Part a\n * unique ID to store the endpoint number for it in the storage to restore the device on restart.\n * In this case we directly use the default command implementation from matter.js. Check out the DeviceNodeFull example\n * to see how to customize the command handlers.\n */\n const endpoint = new Endpoint(isSocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: \"onoff\" });\n await server.add(endpoint);\n\n /**\n * Register state change handlers of the node for identify and onoff states to react to the commands.\n * If the code in these change handlers fail then the change is also rolled back and not executed and an error is\n * reported back to the controller.\n */\n let isIdentifying = false;\n endpoint.events.identify.identifyTime$Change.on(value => {\n // identifyTime is set when an identify command is called and then decreased every second while indentify logic runs.\n if (value > 0 && !isIdentifying) {\n isIdentifying = true;\n console.log(`Run identify logic, ideally blink a light every 0.5s ...`);\n } else if (value === 0) {\n isIdentifying = false;\n console.log(`Stop identify logic ...`);\n }\n });\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? \"on\" : \"off\");\n console.log(`OnOff is now ${value ? \"ON\" : \"OFF\"}`);\n });\n\n /**\n * Log the endpoint structure for debugging reasons and to allow to verify anything is correct\n */\n logEndpoint(EndpointServer.forEndpoint(server));\n\n /**\n * In order to start the node and announce it into the network we use the run method which resolves when the node goes\n * offline again because we do not need anything more here. See the Full example for other starting options.\n * The QR Code is printed automatically.\n */\n await server.run();\n}\n\nmain().catch(error => console.error(error));\n\n/*********************************************************************************************************\n * Convenience Methods\n *********************************************************************************************************/\n\n/** Defined a shell command from an environment variable and execute it and log the response. */\nfunction executeCommand(scriptParamName: string) {\n const script = Environment.default.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\nasync function getConfiguration() {\n /**\n * Collect all needed data\n *\n * This block collects all needed data from cli, environment or storage. Replace this with where ever your data come from.\n *\n * Note: This example uses the matter.js process storage system to store the device parameter data for convenience\n * and easy reuse. When you also do that be careful to not overlap with Matter-Server own storage contexts\n * (so maybe better not do it ;-)).\n */\n const environment = Environment.default;\n\n const storageService = environment.get(StorageService);\n console.log(`Storage location: ${storageService.location} (Directory)`);\n console.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n );\n const deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\n const isSocket = await deviceStorage.get(\"isSocket\", environment.vars.get(\"type\") === \"socket\");\n if (await deviceStorage.has(\"isSocket\")) {\n console.log(`Device type ${isSocket ? \"socket\" : \"light\"} found in storage. --type parameter is ignored.`);\n }\n const deviceName = \"Matter test device\";\n const vendorName = \"matter-node.js\";\n const passcode = environment.vars.number(\"passcode\") ?? (await deviceStorage.get(\"passcode\", 20202021));\n const discriminator = environment.vars.number(\"discriminator\") ?? (await deviceStorage.get(\"discriminator\", 3840));\n // product name / id and vendor id should match what is in the device certificate\n const vendorId = environment.vars.number(\"vendorid\") ?? (await deviceStorage.get(\"vendorid\", 0xfff1));\n const productName = `node-matter OnOff ${isSocket ? \"Socket\" : \"Light\"}`;\n const productId = environment.vars.number(\"productid\") ?? (await deviceStorage.get(\"productid\", 0x8000));\n\n const port = environment.vars.number(\"port\") ?? 5540;\n\n const uniqueId =\n environment.vars.string(\"uniqueid\") ?? (await deviceStorage.get(\"uniqueid\", Time.nowMs())).toString();\n\n // Persist basic data to keep them also on restart\n await deviceStorage.set({\n passcode,\n discriminator,\n vendorid: vendorId,\n productid: productId,\n isSocket,\n uniqueid: uniqueId,\n });\n\n return {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example shows how to create a simple on-off Matter device as a light or as a socket.\n * It can be used as CLI script and starting point for your own device node implementation.\n * This example is CJS conform and do not use top level await's.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { execSync } from \"child_process\";\n\nrequireMinNodeVersion(16);\n\nasync function main() {\n /** Initialize configuration values */\n const {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n } = await getConfiguration();\n\n /**\n * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration\n */\n const server = await ServerNode.create({\n // Required: Give the Node a unique ID which is used to store the state of this node\n id: uniqueId,\n\n // Provide Network relevant configuration like the port\n // Optional when operating only one device on a host, Default port is 5540\n network: {\n port,\n },\n\n // Provide Commissioning relevant settings\n // Optional for development/testing purposes\n commissioning: {\n passcode,\n discriminator,\n },\n\n // Provide Node announcement settings\n // Optional: If Ommitted some development defaults are used\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(isSocket ? OnOffPlugInUnitDevice.deviceType : OnOffLightDevice.deviceType),\n },\n\n // Provide defaults for the BasicInformation cluster on the Root endpoint\n // Optional: If Omitted some development defaults are used\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `matterjs-${uniqueId}`,\n uniqueId,\n },\n });\n\n /**\n * Matter Nodes are a composition of endpoints. Create and add a single endpoint to the node. This example uses the\n * OnOffLightDevice or OnOffPlugInUnitDevice depending on the value of the type parameter. It also assigns this Part a\n * unique ID to store the endpoint number for it in the storage to restore the device on restart.\n * In this case we directly use the default command implementation from matter.js. Check out the DeviceNodeFull example\n * to see how to customize the command handlers.\n */\n const endpoint = new Endpoint(isSocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: \"onoff\" });\n await server.add(endpoint);\n\n /**\n * Register state change handlers and events of the node for identify and onoff states to react to the commands.\n * If the code in these change handlers fail then the change is also rolled back and not executed and an error is\n * reported back to the controller.\n */\n endpoint.events.identify.startIdentifying.on(() => {\n console.log(`Run identify logic, ideally blink a light every 0.5s ...`);\n });\n\n endpoint.events.identify.stopIdentifying.on(() => {\n console.log(`Stop identify logic ...`);\n });\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? \"on\" : \"off\");\n console.log(`OnOff is now ${value ? \"ON\" : \"OFF\"}`);\n });\n\n /**\n * Log the endpoint structure for debugging reasons and to allow to verify anything is correct\n */\n logEndpoint(EndpointServer.forEndpoint(server));\n\n /**\n * In order to start the node and announce it into the network we use the run method which resolves when the node goes\n * offline again because we do not need anything more here. See the Full example for other starting options.\n * The QR Code is printed automatically.\n */\n await server.run();\n}\n\nmain().catch(error => console.error(error));\n\n/*********************************************************************************************************\n * Convenience Methods\n *********************************************************************************************************/\n\n/** Defined a shell command from an environment variable and execute it and log the response. */\nfunction executeCommand(scriptParamName: string) {\n const script = Environment.default.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\nasync function getConfiguration() {\n /**\n * Collect all needed data\n *\n * This block collects all needed data from cli, environment or storage. Replace this with where ever your data come from.\n *\n * Note: This example uses the matter.js process storage system to store the device parameter data for convenience\n * and easy reuse. When you also do that be careful to not overlap with Matter-Server own storage contexts\n * (so maybe better not do it ;-)).\n */\n const environment = Environment.default;\n\n const storageService = environment.get(StorageService);\n console.log(`Storage location: ${storageService.location} (Directory)`);\n console.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n );\n const deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\n const isSocket = await deviceStorage.get(\"isSocket\", environment.vars.get(\"type\") === \"socket\");\n if (await deviceStorage.has(\"isSocket\")) {\n console.log(`Device type ${isSocket ? \"socket\" : \"light\"} found in storage. --type parameter is ignored.`);\n }\n const deviceName = \"Matter test device\";\n const vendorName = \"matter-node.js\";\n const passcode = environment.vars.number(\"passcode\") ?? (await deviceStorage.get(\"passcode\", 20202021));\n const discriminator = environment.vars.number(\"discriminator\") ?? (await deviceStorage.get(\"discriminator\", 3840));\n // product name / id and vendor id should match what is in the device certificate\n const vendorId = environment.vars.number(\"vendorid\") ?? (await deviceStorage.get(\"vendorid\", 0xfff1));\n const productName = `node-matter OnOff ${isSocket ? \"Socket\" : \"Light\"}`;\n const productId = environment.vars.number(\"productid\") ?? (await deviceStorage.get(\"productid\", 0x8000));\n\n const port = environment.vars.number(\"port\") ?? 5540;\n\n const uniqueId =\n environment.vars.string(\"uniqueid\") ?? (await deviceStorage.get(\"uniqueid\", Time.nowMs())).toString();\n\n // Persist basic data to keep them also on restart\n await deviceStorage.set({\n passcode,\n discriminator,\n vendorid: vendorId,\n productid: productId,\n isSocket,\n uniqueid: uniqueId,\n });\n\n return {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -209,15 +209,11 @@ server.events.sessions.subscriptionsChanged.on((session) => {
209
209
  console.log(`Session subscriptions changed`, session);
210
210
  console.log(`Status of all sessions`, server.state.sessions.sessions);
211
211
  });
212
- let isIdentifying = false;
213
- endpoint.events.identify.identifyTime$Change.on((value) => {
214
- if (value > 0 && !isIdentifying) {
215
- isIdentifying = true;
216
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
217
- } else if (value === 0) {
218
- isIdentifying = false;
219
- console.log(`Stop identify logic ...`);
220
- }
212
+ endpoint.events.identify.startIdentifying.on(() => {
213
+ console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
214
+ });
215
+ endpoint.events.identify.stopIdentifying.on(() => {
216
+ console.log(`Stop identify logic ...`);
221
217
  });
222
218
  logEndpoint(EndpointServer.forEndpoint(server));
223
219
  await server.bringOnline();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/examples/DeviceNodeFull.ts"],
4
- "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example is not optimized for simplicity, but to show all the advanced use cases for matter.js.\n * If you want to see a simple minimalistic and more standard example please look at DeviceNode.ts or the other examples.\n *\n * This example shows how to create a simple on-off Matter device as a light or as a socket.\n * It can be used as CLI script and starting point for your own device node implementation.\n * Additional to this it shows the following:\n * * How to modify the existing clusters on Root and also Device Endpoints\n * * How to add own Cluster implementations for Standard clusters\n * * How to add a custom Cluster to an Endpoint\n * * Which events are available to get status information from the Node aon commissioning and session/subscription changes\n * * How to get cluster state values\n * * How to set one or multiple state values in a transaction.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { BleNode } from \"@project-chip/matter-node-ble.js/ble\";\nimport { createFileLogger } from \"@project-chip/matter-node.js/log\";\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { TestEventTriggerRequest } from \"@project-chip/matter.js/behavior/definitions/general-diagnostics\";\nimport { NetworkCommissioningServer } from \"@project-chip/matter.js/behavior/definitions/network-commissioning\";\nimport { OnOffServer } from \"@project-chip/matter.js/behavior/definitions/on-off\";\nimport { Ble } from \"@project-chip/matter.js/ble\";\nimport { NetworkCommissioning } from \"@project-chip/matter.js/cluster\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { RootRequirements } from \"@project-chip/matter.js/endpoint/definitions\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { FabricAction } from \"@project-chip/matter.js/fabric\";\nimport { Level, Logger, levelFromString } from \"@project-chip/matter.js/log\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { QrCode } from \"@project-chip/matter.js/schema\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { ByteArray, singleton } from \"@project-chip/matter.js/util\";\nimport { execSync } from \"child_process\";\nimport { DummyThreadNetworkCommissioningServer } from \"./cluster/DummyThreadNetworkCommissioningServer.js\";\nimport { DummyWifiNetworkCommissioningServer } from \"./cluster/DummyWifiNetworkCommissioningServer.js\";\nimport {\n MyFancyCommandRequest,\n MyFancyCommandResponse,\n MyFancyOwnFunctionalityBehavior,\n} from \"./cluster/MyFancyOwnFunctionality.js\";\n\n/**\n * The following code brings some convenience to the CLI script. It allows to set the log level and format via\n * command line parameters. It also initializes the BLE stack if the `--ble` parameter is present.\n * Some of these parameters can also be replaced by generically accepted parameters or even environment variables. See the comments in the relevant places for information.\n * When using this code as basis for your own device node implementation, you can remove this part or hard code it.\n */\n\nrequireMinNodeVersion(16);\n\n// To configure Logging use\n// * \"--log-level\" or environment variable \"MATTER_LOG_LEVEL\" or \"environment.vars.set('log.level', Level.DEBUG)\"\n// Allowed values are: Level.FATAL, Level.ERROR, Level.WARN, Level.NOTICE, Level.INFO, Level.DEBUG\n// * \"--log-format\" or environment variable \"MATTER_LOG_FORMAT\" or \"environment.vars.set('log.format', Format.PLAIN)\"\n// Allowed values are: Format.PLAIN, Format.HTML, Format.ANSI,\n\nconst environment = Environment.default;\n\n// Alternatively \"--ble-enable\" or environment variable \"BLE_ENABLED\"\n// Alternatively \"--ble-hciId\" or environment variable \"BLE_HCIID\"\nif (environment.vars.get(\"ble.enable\")) {\n // Initialize Ble\n Ble.get = singleton(\n () =>\n new BleNode({\n hciId: environment.vars.number(\"ble.hciId\"),\n }),\n );\n}\n\nfunction executeCommand(scriptParamName: string) {\n const script = environment.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\n/**\n * Collect all needed data\n *\n * This block collects all needed data from cli or storage. Replace this with where ever your data come from.\n *\n * Note: This example uses the matter.js process storage system to store the device parameter data for convenience\n * and easy reuse. When you also do that be careful to not overlap with Matter-Server own storage contexts\n * (so maybe better not do it ;-)).\n */\n\nconst logFile = environment.vars.string(\"logfile.filename\");\nif (logFile !== undefined) {\n Logger.addLogger(\"filelogger\", await createFileLogger(logFile), {\n defaultLogLevel: levelFromString(environment.vars.string(\"logfile.loglevel\")) ?? Level.DEBUG,\n });\n}\n\nconst storageService = environment.get(StorageService);\nconsole.log(`Storage location: ${storageService.location} (Directory)`);\nconsole.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n);\n\nconst deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\nif (await deviceStorage.has(\"isSocket\")) {\n console.log(\"Device type found in storage. --type parameter is ignored.\");\n}\nconst isSocket = await deviceStorage.get(\"isSocket\", environment.vars.string(\"type\") === \"socket\");\nconst deviceName = \"Matter test device\";\nconst vendorName = \"matter-node.js\";\nconst passcode = environment.vars.number(\"passcode\") ?? (await deviceStorage.get(\"passcode\", 20202021));\nconst discriminator = environment.vars.number(\"discriminator\") ?? (await deviceStorage.get(\"discriminator\", 3840));\n// product name / id and vendor id should match what is in the device certificate\nconst vendorId = environment.vars.number(\"vendorid\") ?? (await deviceStorage.get(\"vendorid\", 0xfff1));\nconst productName = `node-matter OnOff ${isSocket ? \"Socket\" : \"Light\"}`;\nconst productId = environment.vars.number(\"productid\") ?? (await deviceStorage.get(\"productid\", 0x8000));\n\nconst port = environment.vars.number(\"port\") ?? 5540;\n\nconst uniqueId = environment.vars.string(\"uniqueid\") ?? (await deviceStorage.get(\"uniqueid\", Time.nowMs().toString()));\n\nawait deviceStorage.set({\n passcode,\n discriminator,\n vendorid: vendorId,\n productid: productId,\n isSocket,\n uniqueid: uniqueId,\n});\n\n// Matter exposes functionality in groups called \"clusters\". For this example device we override the matter.js \"On/Off\"\n// cluster implementation to print status to the console.\nclass OnOffShellExecServer extends OnOffServer {\n // Intercept the \"on\" command to the Matter On/Off cluster to print a log message.\n override on() {\n executeCommand(\"on\");\n super.on();\n }\n\n // This is the functional inverse of on() above.\n //\n // For demonstration purposes we update state ourselves rather than deferring to matter.js's default \"off\" handler\n // via super.off().\n override off() {\n executeCommand(\"off\");\n this.state.onOff = false;\n }\n\n // Use event handlers to log on/off state reactively, after it changes.\n override initialize() {\n this.events.onOff$Change.on(value => {\n console.log(`Light is now ${value ? \"ON\" : \"OFF\"}`);\n });\n }\n}\n\nclass TestGeneralDiagnosticsServer extends RootRequirements.GeneralDiagnosticsServer {\n override initialize() {\n this.state.testEventTriggersEnabled = true; // set to true if you support test triggers ...\n super.initialize();\n }\n\n override testEventTrigger({ enableKey, eventTrigger }: TestEventTriggerRequest) {\n console.log(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`);\n }\n}\n\nclass MyFancyOwnFunctionalityServer extends MyFancyOwnFunctionalityBehavior {\n /** We return the incoming value and store the length of the string in our attribute and send it out as event */\n override myFancyCommand(request: MyFancyCommandRequest): MyFancyCommandResponse {\n const { value } = request;\n this.state.myFancyValue = value.length;\n\n this.events.myFancyEvent.emit({ eventValue: value }, this.context);\n\n return { response: value };\n }\n\n override initialize() {\n this.state.myFancyValue = -1; // Always initialize with -1\n }\n}\n\n/**\n * Create Device instance and add needed Listener\n *\n * Create an instance of the matter device class you want to use.\n * This example uses the OnOffLightDevice or OnOffPluginUnitDevice depending on the value of the type parameter.\n * To execute the on/off scripts defined as parameters a listener for the onOff attribute is registered via the\n * device specific API.\n *\n * The below logic also adds command handlers for commands of clusters that normally are handled device internally\n * like identify that can be implemented with the logic when these commands are called.\n */\n\n// Devices are compositions of behaviors like OnOffServer above. To extend an existing device you use builder methods.\n//\n// In this case we are using with() to install our On/Off cluster behavior.\n// .with(\"LevelControlForLighting\") not needed because we always have it in by default because we have default implementation\nconst OnOffDevice = isSocket\n ? vendorId === 0xfff4\n ? OnOffPlugInUnitDevice.with(OnOffShellExecServer, MyFancyOwnFunctionalityServer)\n : OnOffPlugInUnitDevice.with(OnOffShellExecServer)\n : vendorId === 0xfff4\n ? OnOffLightDevice.with(OnOffShellExecServer, MyFancyOwnFunctionalityServer)\n : OnOffLightDevice.with(OnOffShellExecServer);\n\n/**\n * Modify automatically added clusters of the Root endpoint if needed\n * In this example we change the networkCommissioning cluster into one for \"Wifi only\" devices when BLE is used\n * for commissioning, to demonstrate how to do this.\n * If you want to implement Ethernet only devices that get connected to the network via LAN/Ethernet cable,\n * then all this is not needed.\n * The same as shown here for Wi-Fi is also possible theoretical for Thread only or combined devices.\n */\n\n// We use the Basic Root Endpoint without a NetworkCommissioning cluster\nlet RootEndpoint = ServerNode.RootEndpoint.with(TestGeneralDiagnosticsServer);\n\nlet wifiOrThreadAdded = false;\nif (Ble.enabled) {\n // matter.js will create a Ethernet-only device by default when ut comes to Network Commissioning Features.\n // To offer e.g. a \"Wi-Fi only device\" (or any other combination) we need to override the Network Commissioning\n // cluster and implement all the need handling here. This is a \"static implementation\" for pure demonstration\n // purposes and just \"simulates\" the actions to be done. In a real world implementation this would be done by\n // the device implementor based on the relevant networking stack.\n // The NetworkCommissioningCluster and all logics are described in Matter Core Specifications section 11.8\n if (environment.vars.has(\"ble.wifi.fake\")) {\n RootEndpoint = RootEndpoint.with(DummyWifiNetworkCommissioningServer);\n wifiOrThreadAdded = true;\n } else if (environment.vars.has(\"ble.thread.fake\")) {\n RootEndpoint = RootEndpoint.with(DummyThreadNetworkCommissioningServer);\n wifiOrThreadAdded = true;\n }\n} else {\n RootEndpoint = RootEndpoint.with(\n NetworkCommissioningServer.with(NetworkCommissioning.Feature.EthernetNetworkInterface),\n );\n}\n\nconst networkId = new ByteArray(32);\n// Physical devices appear as \"nodes\" on a Matter network. As a device implementer you use a NodeServer to bring a\n// device online.\n//\n// Note there are a large number of options to NodeServer that we are allowing to take default values here. See\n// CompositeWindowCovering.ts for a more detailed example.\nconst server = await ServerNode.create(RootEndpoint, {\n id: uniqueId,\n network: {\n port,\n discoveryCapabilities: {\n onIpNetwork: !environment.vars.has(\"ble.enable\"),\n ble: environment.vars.has(\"ble.enable\"),\n },\n ble: environment.vars.has(\"ble.enable\"), // TODO remove when state init is fixed\n },\n commissioning: {\n passcode,\n discriminator,\n },\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(OnOffDevice.deviceType),\n },\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `node-matter-${uniqueId}`,\n uniqueId,\n },\n\n // @ts-expect-error ... TS do not see the types because both next clusters was added conditionally\n networkCommissioning: {\n maxNetworks: 1,\n interfaceEnabled: true,\n lastConnectErrorValue: 0,\n lastNetworkId: wifiOrThreadAdded ? null : networkId,\n lastNetworkingStatus: wifiOrThreadAdded ? null : NetworkCommissioning.NetworkCommissioningStatus.Success,\n networks: [{ networkId: networkId, connected: !wifiOrThreadAdded }],\n scanMaxTimeSeconds: wifiOrThreadAdded ? 3 : undefined,\n connectMaxTimeSeconds: wifiOrThreadAdded ? 3 : undefined,\n },\n myFancyFunctionality: {\n myFancyValue: 0,\n },\n});\n\n// Nodes are a composition of endpoints. Add a single endpoint to the node, our example light device.\nconst endpoint = new Endpoint(OnOffDevice, { id: \"onoff\" });\nawait server.add(endpoint);\n\n/**\n * This event is triggered when the device is initially commissioned successfully.\n * This means: It is added to the first fabric.\n */\nserver.lifecycle.commissioned.on(() => console.log(\"Server was initially commissioned successfully!\"));\n\n/** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */\nserver.lifecycle.decommissioned.on(() => console.log(\"Server was fully decommissioned successfully!\"));\n\n/** This event is triggered when the device went online. This means that it is discoverable in the network. */\nserver.lifecycle.online.on(() => console.log(\"Server is online\"));\n\n/** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */\nserver.lifecycle.offline.on(() => console.log(\"Server is offline\"));\n\n/**\n * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular\n * information is needed.\n */\nserver.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {\n let action = \"\";\n switch (fabricAction) {\n case FabricAction.Added:\n action = \"added\";\n break;\n case FabricAction.Removed:\n action = \"removed\";\n break;\n case FabricAction.Updated:\n action = \"updated\";\n break;\n }\n console.log(`Commissioned Fabrics changed event (${action}) for ${fabricIndex} triggered`);\n console.log(server.state.commissioning.fabrics[fabricIndex]);\n});\n\n/**\n * This event is triggered when an operative new session was opened by a Controller.\n * It is not triggered for the initial commissioning process, just afterwards for real connections.\n */\nserver.events.sessions.opened.on(session => console.log(`Session opened`, session));\n\n/**\n * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.\n */\nserver.events.sessions.closed.on(session => console.log(`Session closed`, session));\n\n/** This event is triggered when a subscription gets added or removed on an operative session. */\nserver.events.sessions.subscriptionsChanged.on(session => {\n console.log(`Session subscriptions changed`, session);\n console.log(`Status of all sessions`, server.state.sessions.sessions);\n});\n\n// React on a change of identificationTime to do Identify stuff for the own device\nlet isIdentifying = false;\nendpoint.events.identify.identifyTime$Change.on(value => {\n if (value > 0 && !isIdentifying) {\n isIdentifying = true;\n console.log(`Run identify logic, ideally blink a light every 0.5s ...`);\n } else if (value === 0) {\n isIdentifying = false;\n console.log(`Stop identify logic ...`);\n }\n});\n\n// Our device is now built and we can bring the node online.\n//\n// Note that you may serve multiple nodes from a single process. We only have one, however, so we can use the run()\n// method of the node.\n\nlogEndpoint(EndpointServer.forEndpoint(server));\n\n/**\n * In order to start the node and announce it into the network we start the node. This method resolves when the Matter\n * node enters his online state. Alternatively, we could also use `await server.run()` which\n * resolves when the node goes offline again, but we want to execute code afterwards, so we use start() here\n */\nawait server.bringOnline();\n\nconsole.log(\"Initial Fabrics\", server.state.operationalCredentials.fabrics);\n\n/**\n * If the node is not commissioned already we display the QR code on console. The QR code is also logged\n */\nif (!server.lifecycle.isCommissioned) {\n const { qrPairingCode, manualPairingCode } = server.state.commissioning.pairingCodes;\n\n console.log(QrCode.get(qrPairingCode));\n console.log(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);\n console.log(`Manual pairing code: ${manualPairingCode}`);\n} else {\n console.log(\"Device is already commissioned. Waiting for controllers to connect ...\");\n\n /**\n * Sometimes reading or writing attributes is required. The following code shows how this works.\n * For read it is basically `endpoint.state.clustername.attributename`.\n * The set method allows to set one or multiple values via the structure of also clustername.attributename. When multiple values are set they are considered being one transaction which would be rolled back completely if one value fails to be set.\n */\n\n // Read onOff attribute from onOff cluster\n const onOffValue = endpoint.state.onOff.onOff;\n console.log(`current OnOff attribute: ${onOffValue}`);\n\n if (vendorId === 0xfff4) {\n // Set onOff attribute from OnOff cluster AND the myFancyValue of the MyFancyOwnFunctionality cluster together\n await endpoint.set({\n onOff: {\n onOff: !onOffValue,\n },\n // @ts-expect-error Needed because the Fancy cluster is added conditionally, so TS do not get that it's there.\n myFancyOwnFunctionality: {\n myFancyValue: 36,\n },\n });\n } else {\n // Set onOff attribute from OnOff cluster only\n await endpoint.set({\n onOff: {\n onOff: !onOffValue,\n },\n });\n }\n}\n\n/**\n * To correctly tear down the now we can use server[Symbol.asyncDispose]().\n */\nprocess.on(\"SIGINT\", () => {\n // Clean up on CTRL-C\n server\n .close()\n .then(() => process.exit(0))\n .catch(err => console.error(err));\n});\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example is not optimized for simplicity, but to show all the advanced use cases for matter.js.\n * If you want to see a simple minimalistic and more standard example please look at DeviceNode.ts or the other examples.\n *\n * This example shows how to create a simple on-off Matter device as a light or as a socket.\n * It can be used as CLI script and starting point for your own device node implementation.\n * Additional to this it shows the following:\n * * How to modify the existing clusters on Root and also Device Endpoints\n * * How to add own Cluster implementations for Standard clusters\n * * How to add a custom Cluster to an Endpoint\n * * Which events are available to get status information from the Node aon commissioning and session/subscription changes\n * * How to get cluster state values\n * * How to set one or multiple state values in a transaction.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { BleNode } from \"@project-chip/matter-node-ble.js/ble\";\nimport { createFileLogger } from \"@project-chip/matter-node.js/log\";\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { TestEventTriggerRequest } from \"@project-chip/matter.js/behavior/definitions/general-diagnostics\";\nimport { NetworkCommissioningServer } from \"@project-chip/matter.js/behavior/definitions/network-commissioning\";\nimport { OnOffServer } from \"@project-chip/matter.js/behavior/definitions/on-off\";\nimport { Ble } from \"@project-chip/matter.js/ble\";\nimport { NetworkCommissioning } from \"@project-chip/matter.js/cluster\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { RootRequirements } from \"@project-chip/matter.js/endpoint/definitions\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { FabricAction } from \"@project-chip/matter.js/fabric\";\nimport { Level, Logger, levelFromString } from \"@project-chip/matter.js/log\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { QrCode } from \"@project-chip/matter.js/schema\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { ByteArray, singleton } from \"@project-chip/matter.js/util\";\nimport { execSync } from \"child_process\";\nimport { DummyThreadNetworkCommissioningServer } from \"./cluster/DummyThreadNetworkCommissioningServer.js\";\nimport { DummyWifiNetworkCommissioningServer } from \"./cluster/DummyWifiNetworkCommissioningServer.js\";\nimport {\n MyFancyCommandRequest,\n MyFancyCommandResponse,\n MyFancyOwnFunctionalityBehavior,\n} from \"./cluster/MyFancyOwnFunctionality.js\";\n\n/**\n * The following code brings some convenience to the CLI script. It allows to set the log level and format via\n * command line parameters. It also initializes the BLE stack if the `--ble` parameter is present.\n * Some of these parameters can also be replaced by generically accepted parameters or even environment variables. See the comments in the relevant places for information.\n * When using this code as basis for your own device node implementation, you can remove this part or hard code it.\n */\n\nrequireMinNodeVersion(16);\n\n// To configure Logging use\n// * \"--log-level\" or environment variable \"MATTER_LOG_LEVEL\" or \"environment.vars.set('log.level', Level.DEBUG)\"\n// Allowed values are: Level.FATAL, Level.ERROR, Level.WARN, Level.NOTICE, Level.INFO, Level.DEBUG\n// * \"--log-format\" or environment variable \"MATTER_LOG_FORMAT\" or \"environment.vars.set('log.format', Format.PLAIN)\"\n// Allowed values are: Format.PLAIN, Format.HTML, Format.ANSI,\n\nconst environment = Environment.default;\n\n// Alternatively \"--ble-enable\" or environment variable \"BLE_ENABLED\"\n// Alternatively \"--ble-hciId\" or environment variable \"BLE_HCIID\"\nif (environment.vars.get(\"ble.enable\")) {\n // Initialize Ble\n Ble.get = singleton(\n () =>\n new BleNode({\n hciId: environment.vars.number(\"ble.hciId\"),\n }),\n );\n}\n\nfunction executeCommand(scriptParamName: string) {\n const script = environment.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\n/**\n * Collect all needed data\n *\n * This block collects all needed data from cli or storage. Replace this with where ever your data come from.\n *\n * Note: This example uses the matter.js process storage system to store the device parameter data for convenience\n * and easy reuse. When you also do that be careful to not overlap with Matter-Server own storage contexts\n * (so maybe better not do it ;-)).\n */\n\nconst logFile = environment.vars.string(\"logfile.filename\");\nif (logFile !== undefined) {\n Logger.addLogger(\"filelogger\", await createFileLogger(logFile), {\n defaultLogLevel: levelFromString(environment.vars.string(\"logfile.loglevel\")) ?? Level.DEBUG,\n });\n}\n\nconst storageService = environment.get(StorageService);\nconsole.log(`Storage location: ${storageService.location} (Directory)`);\nconsole.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n);\n\nconst deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\nif (await deviceStorage.has(\"isSocket\")) {\n console.log(\"Device type found in storage. --type parameter is ignored.\");\n}\nconst isSocket = await deviceStorage.get(\"isSocket\", environment.vars.string(\"type\") === \"socket\");\nconst deviceName = \"Matter test device\";\nconst vendorName = \"matter-node.js\";\nconst passcode = environment.vars.number(\"passcode\") ?? (await deviceStorage.get(\"passcode\", 20202021));\nconst discriminator = environment.vars.number(\"discriminator\") ?? (await deviceStorage.get(\"discriminator\", 3840));\n// product name / id and vendor id should match what is in the device certificate\nconst vendorId = environment.vars.number(\"vendorid\") ?? (await deviceStorage.get(\"vendorid\", 0xfff1));\nconst productName = `node-matter OnOff ${isSocket ? \"Socket\" : \"Light\"}`;\nconst productId = environment.vars.number(\"productid\") ?? (await deviceStorage.get(\"productid\", 0x8000));\n\nconst port = environment.vars.number(\"port\") ?? 5540;\n\nconst uniqueId = environment.vars.string(\"uniqueid\") ?? (await deviceStorage.get(\"uniqueid\", Time.nowMs().toString()));\n\nawait deviceStorage.set({\n passcode,\n discriminator,\n vendorid: vendorId,\n productid: productId,\n isSocket,\n uniqueid: uniqueId,\n});\n\n// Matter exposes functionality in groups called \"clusters\". For this example device we override the matter.js \"On/Off\"\n// cluster implementation to print status to the console.\nclass OnOffShellExecServer extends OnOffServer {\n // Intercept the \"on\" command to the Matter On/Off cluster to print a log message.\n override on() {\n executeCommand(\"on\");\n super.on();\n }\n\n // This is the functional inverse of on() above.\n //\n // For demonstration purposes we update state ourselves rather than deferring to matter.js's default \"off\" handler\n // via super.off().\n override off() {\n executeCommand(\"off\");\n this.state.onOff = false;\n }\n\n // Use event handlers to log on/off state reactively, after it changes.\n override initialize() {\n this.events.onOff$Change.on(value => {\n console.log(`Light is now ${value ? \"ON\" : \"OFF\"}`);\n });\n }\n}\n\nclass TestGeneralDiagnosticsServer extends RootRequirements.GeneralDiagnosticsServer {\n override initialize() {\n this.state.testEventTriggersEnabled = true; // set to true if you support test triggers ...\n super.initialize();\n }\n\n override testEventTrigger({ enableKey, eventTrigger }: TestEventTriggerRequest) {\n console.log(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`);\n }\n}\n\nclass MyFancyOwnFunctionalityServer extends MyFancyOwnFunctionalityBehavior {\n /** We return the incoming value and store the length of the string in our attribute and send it out as event */\n override myFancyCommand(request: MyFancyCommandRequest): MyFancyCommandResponse {\n const { value } = request;\n this.state.myFancyValue = value.length;\n\n this.events.myFancyEvent.emit({ eventValue: value }, this.context);\n\n return { response: value };\n }\n\n override initialize() {\n this.state.myFancyValue = -1; // Always initialize with -1\n }\n}\n\n/**\n * Create Device instance and add needed Listener\n *\n * Create an instance of the matter device class you want to use.\n * This example uses the OnOffLightDevice or OnOffPluginUnitDevice depending on the value of the type parameter.\n * To execute the on/off scripts defined as parameters a listener for the onOff attribute is registered via the\n * device specific API.\n *\n * The below logic also adds command handlers for commands of clusters that normally are handled device internally\n * like identify that can be implemented with the logic when these commands are called.\n */\n\n// Devices are compositions of behaviors like OnOffServer above. To extend an existing device you use builder methods.\n//\n// In this case we are using with() to install our On/Off cluster behavior.\n// .with(\"LevelControlForLighting\") not needed because we always have it in by default because we have default implementation\nconst OnOffDevice = isSocket\n ? vendorId === 0xfff4\n ? OnOffPlugInUnitDevice.with(OnOffShellExecServer, MyFancyOwnFunctionalityServer)\n : OnOffPlugInUnitDevice.with(OnOffShellExecServer)\n : vendorId === 0xfff4\n ? OnOffLightDevice.with(OnOffShellExecServer, MyFancyOwnFunctionalityServer)\n : OnOffLightDevice.with(OnOffShellExecServer);\n\n/**\n * Modify automatically added clusters of the Root endpoint if needed\n * In this example we change the networkCommissioning cluster into one for \"Wifi only\" devices when BLE is used\n * for commissioning, to demonstrate how to do this.\n * If you want to implement Ethernet only devices that get connected to the network via LAN/Ethernet cable,\n * then all this is not needed.\n * The same as shown here for Wi-Fi is also possible theoretical for Thread only or combined devices.\n */\n\n// We use the Basic Root Endpoint without a NetworkCommissioning cluster\nlet RootEndpoint = ServerNode.RootEndpoint.with(TestGeneralDiagnosticsServer);\n\nlet wifiOrThreadAdded = false;\nif (Ble.enabled) {\n // matter.js will create a Ethernet-only device by default when ut comes to Network Commissioning Features.\n // To offer e.g. a \"Wi-Fi only device\" (or any other combination) we need to override the Network Commissioning\n // cluster and implement all the need handling here. This is a \"static implementation\" for pure demonstration\n // purposes and just \"simulates\" the actions to be done. In a real world implementation this would be done by\n // the device implementor based on the relevant networking stack.\n // The NetworkCommissioningCluster and all logics are described in Matter Core Specifications section 11.8\n if (environment.vars.has(\"ble.wifi.fake\")) {\n RootEndpoint = RootEndpoint.with(DummyWifiNetworkCommissioningServer);\n wifiOrThreadAdded = true;\n } else if (environment.vars.has(\"ble.thread.fake\")) {\n RootEndpoint = RootEndpoint.with(DummyThreadNetworkCommissioningServer);\n wifiOrThreadAdded = true;\n }\n} else {\n RootEndpoint = RootEndpoint.with(\n NetworkCommissioningServer.with(NetworkCommissioning.Feature.EthernetNetworkInterface),\n );\n}\n\nconst networkId = new ByteArray(32);\n// Physical devices appear as \"nodes\" on a Matter network. As a device implementer you use a NodeServer to bring a\n// device online.\n//\n// Note there are a large number of options to NodeServer that we are allowing to take default values here. See\n// CompositeWindowCovering.ts for a more detailed example.\nconst server = await ServerNode.create(RootEndpoint, {\n id: uniqueId,\n network: {\n port,\n discoveryCapabilities: {\n onIpNetwork: !environment.vars.has(\"ble.enable\"),\n ble: environment.vars.has(\"ble.enable\"),\n },\n ble: environment.vars.has(\"ble.enable\"), // TODO remove when state init is fixed\n },\n commissioning: {\n passcode,\n discriminator,\n },\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(OnOffDevice.deviceType),\n },\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `node-matter-${uniqueId}`,\n uniqueId,\n },\n\n // @ts-expect-error ... TS do not see the types because both next clusters was added conditionally\n networkCommissioning: {\n maxNetworks: 1,\n interfaceEnabled: true,\n lastConnectErrorValue: 0,\n lastNetworkId: wifiOrThreadAdded ? null : networkId,\n lastNetworkingStatus: wifiOrThreadAdded ? null : NetworkCommissioning.NetworkCommissioningStatus.Success,\n networks: [{ networkId: networkId, connected: !wifiOrThreadAdded }],\n scanMaxTimeSeconds: wifiOrThreadAdded ? 3 : undefined,\n connectMaxTimeSeconds: wifiOrThreadAdded ? 3 : undefined,\n },\n myFancyFunctionality: {\n myFancyValue: 0,\n },\n});\n\n// Nodes are a composition of endpoints. Add a single endpoint to the node, our example light device.\nconst endpoint = new Endpoint(OnOffDevice, { id: \"onoff\" });\nawait server.add(endpoint);\n\n/**\n * This event is triggered when the device is initially commissioned successfully.\n * This means: It is added to the first fabric.\n */\nserver.lifecycle.commissioned.on(() => console.log(\"Server was initially commissioned successfully!\"));\n\n/** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */\nserver.lifecycle.decommissioned.on(() => console.log(\"Server was fully decommissioned successfully!\"));\n\n/** This event is triggered when the device went online. This means that it is discoverable in the network. */\nserver.lifecycle.online.on(() => console.log(\"Server is online\"));\n\n/** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */\nserver.lifecycle.offline.on(() => console.log(\"Server is offline\"));\n\n/**\n * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular\n * information is needed.\n */\nserver.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {\n let action = \"\";\n switch (fabricAction) {\n case FabricAction.Added:\n action = \"added\";\n break;\n case FabricAction.Removed:\n action = \"removed\";\n break;\n case FabricAction.Updated:\n action = \"updated\";\n break;\n }\n console.log(`Commissioned Fabrics changed event (${action}) for ${fabricIndex} triggered`);\n console.log(server.state.commissioning.fabrics[fabricIndex]);\n});\n\n/**\n * This event is triggered when an operative new session was opened by a Controller.\n * It is not triggered for the initial commissioning process, just afterwards for real connections.\n */\nserver.events.sessions.opened.on(session => console.log(`Session opened`, session));\n\n/**\n * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.\n */\nserver.events.sessions.closed.on(session => console.log(`Session closed`, session));\n\n/** This event is triggered when a subscription gets added or removed on an operative session. */\nserver.events.sessions.subscriptionsChanged.on(session => {\n console.log(`Session subscriptions changed`, session);\n console.log(`Status of all sessions`, server.state.sessions.sessions);\n});\n\n// React on a change of identificationTime to do Identify stuff for the own device\nendpoint.events.identify.startIdentifying.on(() => {\n console.log(`Run identify logic, ideally blink a light every 0.5s ...`);\n});\n\nendpoint.events.identify.stopIdentifying.on(() => {\n console.log(`Stop identify logic ...`);\n});\n\n// Our device is now built and we can bring the node online.\n//\n// Note that you may serve multiple nodes from a single process. We only have one, however, so we can use the run()\n// method of the node.\n\nlogEndpoint(EndpointServer.forEndpoint(server));\n\n/**\n * In order to start the node and announce it into the network we start the node. This method resolves when the Matter\n * node enters his online state. Alternatively, we could also use `await server.run()` which\n * resolves when the node goes offline again, but we want to execute code afterwards, so we use start() here\n */\nawait server.bringOnline();\n\nconsole.log(\"Initial Fabrics\", server.state.operationalCredentials.fabrics);\n\n/**\n * If the node is not commissioned already we display the QR code on console. The QR code is also logged\n */\nif (!server.lifecycle.isCommissioned) {\n const { qrPairingCode, manualPairingCode } = server.state.commissioning.pairingCodes;\n\n console.log(QrCode.get(qrPairingCode));\n console.log(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);\n console.log(`Manual pairing code: ${manualPairingCode}`);\n} else {\n console.log(\"Device is already commissioned. Waiting for controllers to connect ...\");\n\n /**\n * Sometimes reading or writing attributes is required. The following code shows how this works.\n * For read it is basically `endpoint.state.clustername.attributename`.\n * The set method allows to set one or multiple values via the structure of also clustername.attributename. When multiple values are set they are considered being one transaction which would be rolled back completely if one value fails to be set.\n */\n\n // Read onOff attribute from onOff cluster\n const onOffValue = endpoint.state.onOff.onOff;\n console.log(`current OnOff attribute: ${onOffValue}`);\n\n if (vendorId === 0xfff4) {\n // Set onOff attribute from OnOff cluster AND the myFancyValue of the MyFancyOwnFunctionality cluster together\n await endpoint.set({\n onOff: {\n onOff: !onOffValue,\n },\n // @ts-expect-error Needed because the Fancy cluster is added conditionally, so TS do not get that it's there.\n myFancyOwnFunctionality: {\n myFancyValue: 36,\n },\n });\n } else {\n // Set onOff attribute from OnOff cluster only\n await endpoint.set({\n onOff: {\n onOff: !onOffValue,\n },\n });\n }\n}\n\n/**\n * To correctly tear down the now we can use server[Symbol.asyncDispose]().\n */\nprocess.on(\"SIGINT\", () => {\n // Clean up on CTRL-C\n server\n .close()\n .then(() => process.exit(0))\n .catch(err => console.error(err));\n});\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -20,7 +20,7 @@ class RollerShade extends LiftingWindowCoveringServer {
20
20
  this.state.targetPositionLiftPercent100ths = position ?? 0;
21
21
  }
22
22
  async initialize() {
23
- this.reactTo(this.events.targetPositionLiftPercent100ths$Change, this.writeTargetToMotor);
23
+ this.reactTo(this.events.targetPositionLiftPercent100ths$Change, this.writeTargetToMotor, { offline: true });
24
24
  await this.readTargetFromMotor();
25
25
  if (this.targetPos === null) {
26
26
  this.targetPos = this.currentPos;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/examples/IlluminatedRollerShade.ts"],
4
- "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { GoToLiftPercentageRequest, WindowCoveringServer } from \"@project-chip/matter.js/behaviors/window-covering\";\nimport { OnOffLightDevice, OnOffLightRequirements } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { WindowCoveringDevice } from \"@project-chip/matter.js/devices/WindowCoveringDevice\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\n\n/**\n * This example demonstrates implementation of a \"composed\" device comprising multiple sub-devices\n *\n * Our example device, the Excelsior 1000 EZ-Nite\u2122, is a roller shade with an illuminated valance.\n */\n\nconst LiftingWindowCoveringServer = WindowCoveringServer.with(\"Lift\", \"AbsolutePosition\", \"PositionAwareLift\");\n\n/**\n * Implementation of the Matter WindowCovering cluster for the shade motor.\n *\n * TODO - some of this should probably move to WindowCoveringServer\n */\nclass RollerShade extends LiftingWindowCoveringServer {\n get currentPos() {\n return this.state.currentPositionLiftPercent100ths ?? 0;\n }\n\n get targetPos() {\n return this.state.targetPositionLiftPercent100ths ?? 0;\n }\n\n set targetPos(position: number) {\n this.state.targetPositionLiftPercent100ths = position ?? 0;\n }\n\n override async initialize() {\n this.reactTo(this.events.targetPositionLiftPercent100ths$Change, this.writeTargetToMotor);\n\n await this.readTargetFromMotor();\n if (this.targetPos === null) {\n this.targetPos = this.currentPos;\n }\n }\n\n override upOrOpen() {\n // 0 = 0%, fully open\n this.targetPos = 0;\n }\n\n override downOrClose() {\n // 10000 = 100%, fully closed\n this.targetPos = 10000;\n }\n\n override stopMotion() {\n this.targetPos = this.currentPos;\n }\n\n override goToLiftPercentage(this: RollerShade, request: GoToLiftPercentageRequest) {\n this.targetPos = request.liftPercent100thsValue;\n }\n\n protected async writeTargetToMotor() {\n // For this contrived example we just log the target position and don't actually animate our fake roller shade\n console.log(\"Window covering target position is now\", `${this.targetPos / 100}%`);\n }\n\n protected async readTargetFromMotor() {\n // Our fake shade is stuck open\n this.state.currentPositionLiftPercent100ths = 0;\n }\n\n protected set currentPos(value: number) {\n this.state.currentPositionLiftPercent100ths = value;\n }\n}\n\n/**\n * Implementation of the OnOff cluster for our valance light.\n */\nclass ValanceLight extends OnOffLightRequirements.OnOffServer {\n override initialize() {\n this.reactTo(this.events.onOff$Change, this.#stateChanged);\n }\n\n #stateChanged(value: boolean) {\n console.log(`Valance is now ${value ? \"illuminated\" : \"dark\"}`);\n }\n}\n\n/**\n * Our Matter node.\n */\nconst node = new ServerNode({\n id: \"excelsior1000\",\n\n productDescription: {},\n\n commissioning: {\n passcode: 20202021,\n discriminator: 3840,\n },\n\n basicInformation: {\n vendorName: \"Acme Corporation\",\n productName: \"Excelsior 1000 EZ-Nite\u2122\",\n vendorId: 0xfff1,\n productId: 0x8000,\n serialNumber: \"1234-12345-123\",\n },\n\n parts: [\n {\n type: WindowCoveringDevice.with(RollerShade),\n id: \"shade\",\n },\n\n {\n type: OnOffLightDevice.with(ValanceLight),\n id: \"valance\",\n },\n ],\n});\n\nawait node.run();\n"],
5
- "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,OAAO;AAEP,SAAoC,4BAA4B;AAChE,SAAS,kBAAkB,8BAA8B;AACzD,SAAS,4BAA4B;AACrC,SAAS,kBAAkB;AAQ3B,MAAM,8BAA8B,qBAAqB,KAAK,QAAQ,oBAAoB,mBAAmB;AAO7G,MAAM,oBAAoB,4BAA4B;AAAA,EAClD,IAAI,aAAa;AACb,WAAO,KAAK,MAAM,oCAAoC;AAAA,EAC1D;AAAA,EAEA,IAAI,YAAY;AACZ,WAAO,KAAK,MAAM,mCAAmC;AAAA,EACzD;AAAA,EAEA,IAAI,UAAU,UAAkB;AAC5B,SAAK,MAAM,kCAAkC,YAAY;AAAA,EAC7D;AAAA,EAEA,MAAe,aAAa;AACxB,SAAK,QAAQ,KAAK,OAAO,wCAAwC,KAAK,kBAAkB;AAExF,UAAM,KAAK,oBAAoB;AAC/B,QAAI,KAAK,cAAc,MAAM;AACzB,WAAK,YAAY,KAAK;AAAA,IAC1B;AAAA,EACJ;AAAA,EAES,WAAW;AAEhB,SAAK,YAAY;AAAA,EACrB;AAAA,EAES,cAAc;AAEnB,SAAK,YAAY;AAAA,EACrB;AAAA,EAES,aAAa;AAClB,SAAK,YAAY,KAAK;AAAA,EAC1B;AAAA,EAES,mBAAsC,SAAoC;AAC/E,SAAK,YAAY,QAAQ;AAAA,EAC7B;AAAA,EAEA,MAAgB,qBAAqB;AAEjC,YAAQ,IAAI,0CAA0C,GAAG,KAAK,YAAY,GAAG,GAAG;AAAA,EACpF;AAAA,EAEA,MAAgB,sBAAsB;AAElC,SAAK,MAAM,mCAAmC;AAAA,EAClD;AAAA,EAEA,IAAc,WAAW,OAAe;AACpC,SAAK,MAAM,mCAAmC;AAAA,EAClD;AACJ;AAKA,MAAM,qBAAqB,uBAAuB,YAAY;AAAA,EACjD,aAAa;AAClB,SAAK,QAAQ,KAAK,OAAO,cAAc,KAAK,aAAa;AAAA,EAC7D;AAAA,EAEA,cAAc,OAAgB;AAC1B,YAAQ,IAAI,kBAAkB,QAAQ,gBAAgB,MAAM,EAAE;AAAA,EAClE;AACJ;AAKA,MAAM,OAAO,IAAI,WAAW;AAAA,EACxB,IAAI;AAAA,EAEJ,oBAAoB,CAAC;AAAA,EAErB,eAAe;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,EACnB;AAAA,EAEA,kBAAkB;AAAA,IACd,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW;AAAA,IACX,cAAc;AAAA,EAClB;AAAA,EAEA,OAAO;AAAA,IACH;AAAA,MACI,MAAM,qBAAqB,KAAK,WAAW;AAAA,MAC3C,IAAI;AAAA,IACR;AAAA,IAEA;AAAA,MACI,MAAM,iBAAiB,KAAK,YAAY;AAAA,MACxC,IAAI;AAAA,IACR;AAAA,EACJ;AACJ,CAAC;AAED,MAAM,KAAK,IAAI;",
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { GoToLiftPercentageRequest, WindowCoveringServer } from \"@project-chip/matter.js/behaviors/window-covering\";\nimport { OnOffLightDevice, OnOffLightRequirements } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { WindowCoveringDevice } from \"@project-chip/matter.js/devices/WindowCoveringDevice\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\n\n/**\n * This example demonstrates implementation of a \"composed\" device comprising multiple sub-devices\n *\n * Our example device, the Excelsior 1000 EZ-Nite\u2122, is a roller shade with an illuminated valance.\n */\n\nconst LiftingWindowCoveringServer = WindowCoveringServer.with(\"Lift\", \"AbsolutePosition\", \"PositionAwareLift\");\n\n/**\n * Implementation of the Matter WindowCovering cluster for the shade motor.\n *\n * TODO - some of this should probably move to WindowCoveringServer\n */\nclass RollerShade extends LiftingWindowCoveringServer {\n get currentPos() {\n return this.state.currentPositionLiftPercent100ths ?? 0;\n }\n\n get targetPos() {\n return this.state.targetPositionLiftPercent100ths ?? 0;\n }\n\n set targetPos(position: number) {\n this.state.targetPositionLiftPercent100ths = position ?? 0;\n }\n\n override async initialize() {\n this.reactTo(this.events.targetPositionLiftPercent100ths$Change, this.writeTargetToMotor, { offline: true });\n\n await this.readTargetFromMotor();\n if (this.targetPos === null) {\n this.targetPos = this.currentPos;\n }\n }\n\n override upOrOpen() {\n // 0 = 0%, fully open\n this.targetPos = 0;\n }\n\n override downOrClose() {\n // 10000 = 100%, fully closed\n this.targetPos = 10000;\n }\n\n override stopMotion() {\n this.targetPos = this.currentPos;\n }\n\n override goToLiftPercentage(this: RollerShade, request: GoToLiftPercentageRequest) {\n this.targetPos = request.liftPercent100thsValue;\n }\n\n protected async writeTargetToMotor() {\n // For this contrived example we just log the target position and don't actually animate our fake roller shade\n console.log(\"Window covering target position is now\", `${this.targetPos / 100}%`);\n }\n\n protected async readTargetFromMotor() {\n // Our fake shade is stuck open\n this.state.currentPositionLiftPercent100ths = 0;\n }\n\n protected set currentPos(value: number) {\n this.state.currentPositionLiftPercent100ths = value;\n }\n}\n\n/**\n * Implementation of the OnOff cluster for our valance light.\n */\nclass ValanceLight extends OnOffLightRequirements.OnOffServer {\n override initialize() {\n this.reactTo(this.events.onOff$Change, this.#stateChanged);\n }\n\n #stateChanged(value: boolean) {\n console.log(`Valance is now ${value ? \"illuminated\" : \"dark\"}`);\n }\n}\n\n/**\n * Our Matter node.\n */\nconst node = new ServerNode({\n id: \"excelsior1000\",\n\n productDescription: {},\n\n commissioning: {\n passcode: 20202021,\n discriminator: 3840,\n },\n\n basicInformation: {\n vendorName: \"Acme Corporation\",\n productName: \"Excelsior 1000 EZ-Nite\u2122\",\n vendorId: 0xfff1,\n productId: 0x8000,\n serialNumber: \"1234-12345-123\",\n },\n\n parts: [\n {\n type: WindowCoveringDevice.with(RollerShade),\n id: \"shade\",\n },\n\n {\n type: OnOffLightDevice.with(ValanceLight),\n id: \"valance\",\n },\n ],\n});\n\nawait node.run();\n"],
5
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,OAAO;AAEP,SAAoC,4BAA4B;AAChE,SAAS,kBAAkB,8BAA8B;AACzD,SAAS,4BAA4B;AACrC,SAAS,kBAAkB;AAQ3B,MAAM,8BAA8B,qBAAqB,KAAK,QAAQ,oBAAoB,mBAAmB;AAO7G,MAAM,oBAAoB,4BAA4B;AAAA,EAClD,IAAI,aAAa;AACb,WAAO,KAAK,MAAM,oCAAoC;AAAA,EAC1D;AAAA,EAEA,IAAI,YAAY;AACZ,WAAO,KAAK,MAAM,mCAAmC;AAAA,EACzD;AAAA,EAEA,IAAI,UAAU,UAAkB;AAC5B,SAAK,MAAM,kCAAkC,YAAY;AAAA,EAC7D;AAAA,EAEA,MAAe,aAAa;AACxB,SAAK,QAAQ,KAAK,OAAO,wCAAwC,KAAK,oBAAoB,EAAE,SAAS,KAAK,CAAC;AAE3G,UAAM,KAAK,oBAAoB;AAC/B,QAAI,KAAK,cAAc,MAAM;AACzB,WAAK,YAAY,KAAK;AAAA,IAC1B;AAAA,EACJ;AAAA,EAES,WAAW;AAEhB,SAAK,YAAY;AAAA,EACrB;AAAA,EAES,cAAc;AAEnB,SAAK,YAAY;AAAA,EACrB;AAAA,EAES,aAAa;AAClB,SAAK,YAAY,KAAK;AAAA,EAC1B;AAAA,EAES,mBAAsC,SAAoC;AAC/E,SAAK,YAAY,QAAQ;AAAA,EAC7B;AAAA,EAEA,MAAgB,qBAAqB;AAEjC,YAAQ,IAAI,0CAA0C,GAAG,KAAK,YAAY,GAAG,GAAG;AAAA,EACpF;AAAA,EAEA,MAAgB,sBAAsB;AAElC,SAAK,MAAM,mCAAmC;AAAA,EAClD;AAAA,EAEA,IAAc,WAAW,OAAe;AACpC,SAAK,MAAM,mCAAmC;AAAA,EAClD;AACJ;AAKA,MAAM,qBAAqB,uBAAuB,YAAY;AAAA,EACjD,aAAa;AAClB,SAAK,QAAQ,KAAK,OAAO,cAAc,KAAK,aAAa;AAAA,EAC7D;AAAA,EAEA,cAAc,OAAgB;AAC1B,YAAQ,IAAI,kBAAkB,QAAQ,gBAAgB,MAAM,EAAE;AAAA,EAClE;AACJ;AAKA,MAAM,OAAO,IAAI,WAAW;AAAA,EACxB,IAAI;AAAA,EAEJ,oBAAoB,CAAC;AAAA,EAErB,eAAe;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,EACnB;AAAA,EAEA,kBAAkB;AAAA,IACd,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW;AAAA,IACX,cAAc;AAAA,EAClB;AAAA,EAEA,OAAO;AAAA,IACH;AAAA,MACI,MAAM,qBAAqB,KAAK,WAAW;AAAA,MAC3C,IAAI;AAAA,IACR;AAAA,IAEA;AAAA,MACI,MAAM,iBAAiB,KAAK,YAAY;AAAA,MACxC,IAAI;AAAA,IACR;AAAA,EACJ;AACJ,CAAC;AAED,MAAM,KAAK,IAAI;",
6
6
  "names": []
7
7
  }
@@ -68,15 +68,11 @@ for (let idx = 1; idx < devices.length; idx++) {
68
68
  );
69
69
  const endpoint = new Endpoint(isSocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: "onoff" });
70
70
  await server.add(endpoint);
71
- let isIdentifying = false;
72
- endpoint.events.identify.identifyTime$Change.on((value) => {
73
- if (value > 0 && !isIdentifying) {
74
- isIdentifying = true;
75
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
76
- } else if (value === 0) {
77
- isIdentifying = false;
78
- console.log(`Stop identify logic ...`);
79
- }
71
+ endpoint.events.identify.startIdentifying.on(() => {
72
+ console.log(`Run identify logic for device ${i}, ideally blink a light every 0.5s ...`);
73
+ });
74
+ endpoint.events.identify.stopIdentifying.on(() => {
75
+ console.log(`Stop identify logic for device ${i}...`);
80
76
  });
81
77
  endpoint.events.onOff.onOff$Change.on((value) => {
82
78
  executeCommand(value ? `on${i}` : `off${i}`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/examples/MultiDeviceNode.ts"],
4
- "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example shows how to create a new device node that is composed of multiple devices.\n * It creates multiple endpoints on the server. For information on how to add a composed device to a bridge please\n * refer to the bridge example!\n * It can be used as CLI script and starting point for your own device node implementation.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { execSync } from \"child_process\";\n\nrequireMinNodeVersion(16);\n\nconst devices = await getConfiguration();\nfor (let idx = 1; idx < devices.length; idx++) {\n const {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n } = devices[idx];\n const i = idx + 1;\n\n /**\n * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration\n */\n const server = await ServerNode.create({\n // Required: Give the Node a unique ID which is used to store the state of this node\n id: uniqueId,\n\n // Provide Network relevant configuration like the port\n // Optional when operating only one device on a host, Default port is 5540\n network: {\n port,\n },\n\n // Provide Commissioning relevant settings\n // Optional for development/testing purposes\n commissioning: {\n passcode,\n discriminator,\n },\n\n // Provide Node announcement settings\n // Optional: If Ommitted some development defaults are used\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(isSocket ? OnOffPlugInUnitDevice.deviceType : OnOffLightDevice.deviceType),\n },\n\n // Provide defaults for the BasicInformation cluster on the Root endpoint\n // Optional: If Omitted some development defaults are used\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `matterjs-${uniqueId}`,\n uniqueId,\n },\n });\n\n console.log(\n `Added device ${i} on port ${port} and unique id ${uniqueId}: Passcode: ${passcode}, Discriminator: ${discriminator}`,\n );\n\n const endpoint = new Endpoint(isSocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: \"onoff\" });\n await server.add(endpoint);\n\n /**\n * Register state change handlers of the node for identify and onoff states to react to the commands.\n * If the code in these change handlers fail then the change is also rolled back and not executed and an error is\n * reported back to the controller.\n */\n let isIdentifying = false;\n endpoint.events.identify.identifyTime$Change.on(value => {\n // identifyTime is set when an identify commandf is called and then decreased every second while indenitfy logic runs.\n if (value > 0 && !isIdentifying) {\n isIdentifying = true;\n console.log(`Run identify logic, ideally blink a light every 0.5s ...`);\n } else if (value === 0) {\n isIdentifying = false;\n console.log(`Stop identify logic ...`);\n }\n });\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? `on${i}` : `off${i}`);\n console.log(`OnOff ${i} is now ${value ? \"ON\" : \"OFF\"}`);\n });\n\n /**\n * Log the endpoint structure for debugging reasons and to allow to verify anything is correct\n */\n logEndpoint(EndpointServer.forEndpoint(server));\n\n console.log(\"----------------------------\");\n console.log(`QR Code for Device ${i} on port ${port}:`);\n console.log(\"----------------------------\");\n\n /**\n * In order to start the node and announce it into the network we use the run method which resolves when the node goes\n * offline again because we do not need anything more here. See the Full example for other starting options.\n * The QR Code is printed automatically.\n */\n await server.bringOnline();\n}\n\n/*********************************************************************************************************\n * Convenience Methods\n *********************************************************************************************************/\n\n/**\n * Defines a shell command from an environment variable and execute it and log the response\n */\nfunction executeCommand(scriptParamName: string) {\n const script = Environment.default.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\nasync function getConfiguration() {\n const environment = Environment.default;\n\n const storageService = environment.get(StorageService);\n console.log(`Storage location: ${storageService.location} (Directory)`);\n console.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n );\n const deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\n let defaultPasscode = 20202021;\n let defaultDiscriminator = 3840;\n let defaultPort = 5550;\n\n const devices = [];\n const numDevices = environment.vars.number(\"num\") ?? 2;\n for (let i = 1; i <= numDevices; i++) {\n const isSocket = await deviceStorage.get(`isSocket${i}`, environment.vars.string(`type${i}`) === \"socket\");\n if (await deviceStorage.has(`isSocket${i}`)) {\n console.log(`Device type ${isSocket ? \"socket\" : \"light\"} found in storage. --type parameter is ignored.`);\n }\n const deviceName = `Matter ${environment.vars.string(`type${i}`) ?? \"light\"} device ${i}`;\n const vendorName = \"matter-node.js\";\n const passcode =\n environment.vars.number(`passcode${i}`) ?? (await deviceStorage.get(`passcode${i}`, defaultPasscode++));\n const discriminator =\n environment.vars.number(`discriminator${i}`) ??\n (await deviceStorage.get(`discriminator${i}`, defaultDiscriminator++));\n // product name / id and vendor id should match what is in the device certificate\n const vendorId = environment.vars.number(`vendorid${i}`) ?? (await deviceStorage.get(`vendorid${i}`, 0xfff1));\n const productName = `node-matter OnOff-Device ${i}`;\n const productId =\n environment.vars.number(`productid${i}`) ?? (await deviceStorage.get(`productid${i}`, 0x8000));\n\n const port = environment.vars.number(`port${i}`) ?? defaultPort++;\n\n const uniqueId =\n environment.vars.string(`uniqueid${i}`) ??\n (await deviceStorage.get(`uniqueid${i}`, `${i}-${Time.nowMs()}`));\n\n // Persist basic data to keep them also on restart\n await deviceStorage.set(`passcode${i}`, passcode);\n await deviceStorage.set(`discriminator${i}`, discriminator);\n await deviceStorage.set(`vendorid${i}`, vendorId);\n await deviceStorage.set(`productid${i}`, productId);\n await deviceStorage.set(`isSocket${i}`, isSocket);\n await deviceStorage.set(`uniqueid${i}`, uniqueId);\n\n devices.push({\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n });\n }\n\n return devices;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * This example shows how to create a new device node that is composed of multiple devices.\n * It creates multiple endpoints on the server. For information on how to add a composed device to a bridge please\n * refer to the bridge example!\n * It can be used as CLI script and starting point for your own device node implementation.\n */\n\n/**\n * Import needed modules from @project-chip/matter-node.js\n */\n// Include this first to auto-register Crypto, Network and Time Node.js implementations\nimport \"@project-chip/matter-node.js\";\n\nimport { requireMinNodeVersion } from \"@project-chip/matter-node.js/util\";\nimport { DeviceTypeId, VendorId } from \"@project-chip/matter.js/datatype\";\nimport { logEndpoint } from \"@project-chip/matter.js/device\";\nimport { OnOffLightDevice } from \"@project-chip/matter.js/devices/OnOffLightDevice\";\nimport { OnOffPlugInUnitDevice } from \"@project-chip/matter.js/devices/OnOffPlugInUnitDevice\";\nimport { Endpoint, EndpointServer } from \"@project-chip/matter.js/endpoint\";\nimport { Environment, StorageService } from \"@project-chip/matter.js/environment\";\nimport { ServerNode } from \"@project-chip/matter.js/node\";\nimport { Time } from \"@project-chip/matter.js/time\";\nimport { execSync } from \"child_process\";\n\nrequireMinNodeVersion(16);\n\nconst devices = await getConfiguration();\nfor (let idx = 1; idx < devices.length; idx++) {\n const {\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n } = devices[idx];\n const i = idx + 1;\n\n /**\n * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration\n */\n const server = await ServerNode.create({\n // Required: Give the Node a unique ID which is used to store the state of this node\n id: uniqueId,\n\n // Provide Network relevant configuration like the port\n // Optional when operating only one device on a host, Default port is 5540\n network: {\n port,\n },\n\n // Provide Commissioning relevant settings\n // Optional for development/testing purposes\n commissioning: {\n passcode,\n discriminator,\n },\n\n // Provide Node announcement settings\n // Optional: If Ommitted some development defaults are used\n productDescription: {\n name: deviceName,\n deviceType: DeviceTypeId(isSocket ? OnOffPlugInUnitDevice.deviceType : OnOffLightDevice.deviceType),\n },\n\n // Provide defaults for the BasicInformation cluster on the Root endpoint\n // Optional: If Omitted some development defaults are used\n basicInformation: {\n vendorName,\n vendorId: VendorId(vendorId),\n nodeLabel: productName,\n productName,\n productLabel: productName,\n productId,\n serialNumber: `matterjs-${uniqueId}`,\n uniqueId,\n },\n });\n\n console.log(\n `Added device ${i} on port ${port} and unique id ${uniqueId}: Passcode: ${passcode}, Discriminator: ${discriminator}`,\n );\n\n const endpoint = new Endpoint(isSocket ? OnOffPlugInUnitDevice : OnOffLightDevice, { id: \"onoff\" });\n await server.add(endpoint);\n\n /**\n * Register state change handlers of the node for identify and onoff states to react to the commands.\n * If the code in these change handlers fail then the change is also rolled back and not executed and an error is\n * reported back to the controller.\n */\n endpoint.events.identify.startIdentifying.on(() => {\n console.log(`Run identify logic for device ${i}, ideally blink a light every 0.5s ...`);\n });\n\n endpoint.events.identify.stopIdentifying.on(() => {\n console.log(`Stop identify logic for device ${i}...`);\n });\n\n endpoint.events.onOff.onOff$Change.on(value => {\n executeCommand(value ? `on${i}` : `off${i}`);\n console.log(`OnOff ${i} is now ${value ? \"ON\" : \"OFF\"}`);\n });\n\n /**\n * Log the endpoint structure for debugging reasons and to allow to verify anything is correct\n */\n logEndpoint(EndpointServer.forEndpoint(server));\n\n console.log(\"----------------------------\");\n console.log(`QR Code for Device ${i} on port ${port}:`);\n console.log(\"----------------------------\");\n\n /**\n * In order to start the node and announce it into the network we use the run method which resolves when the node goes\n * offline again because we do not need anything more here. See the Full example for other starting options.\n * The QR Code is printed automatically.\n */\n await server.bringOnline();\n}\n\n/*********************************************************************************************************\n * Convenience Methods\n *********************************************************************************************************/\n\n/**\n * Defines a shell command from an environment variable and execute it and log the response\n */\nfunction executeCommand(scriptParamName: string) {\n const script = Environment.default.vars.string(scriptParamName);\n if (script === undefined) return undefined;\n console.log(`${scriptParamName}: ${execSync(script).toString().slice(0, -1)}`);\n}\n\nasync function getConfiguration() {\n const environment = Environment.default;\n\n const storageService = environment.get(StorageService);\n console.log(`Storage location: ${storageService.location} (Directory)`);\n console.log(\n 'Use the parameter \"--storage-path=NAME-OR-PATH\" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',\n );\n const deviceStorage = (await storageService.open(\"device\")).createContext(\"data\");\n\n let defaultPasscode = 20202021;\n let defaultDiscriminator = 3840;\n let defaultPort = 5550;\n\n const devices = [];\n const numDevices = environment.vars.number(\"num\") ?? 2;\n for (let i = 1; i <= numDevices; i++) {\n const isSocket = await deviceStorage.get(`isSocket${i}`, environment.vars.string(`type${i}`) === \"socket\");\n if (await deviceStorage.has(`isSocket${i}`)) {\n console.log(`Device type ${isSocket ? \"socket\" : \"light\"} found in storage. --type parameter is ignored.`);\n }\n const deviceName = `Matter ${environment.vars.string(`type${i}`) ?? \"light\"} device ${i}`;\n const vendorName = \"matter-node.js\";\n const passcode =\n environment.vars.number(`passcode${i}`) ?? (await deviceStorage.get(`passcode${i}`, defaultPasscode++));\n const discriminator =\n environment.vars.number(`discriminator${i}`) ??\n (await deviceStorage.get(`discriminator${i}`, defaultDiscriminator++));\n // product name / id and vendor id should match what is in the device certificate\n const vendorId = environment.vars.number(`vendorid${i}`) ?? (await deviceStorage.get(`vendorid${i}`, 0xfff1));\n const productName = `node-matter OnOff-Device ${i}`;\n const productId =\n environment.vars.number(`productid${i}`) ?? (await deviceStorage.get(`productid${i}`, 0x8000));\n\n const port = environment.vars.number(`port${i}`) ?? defaultPort++;\n\n const uniqueId =\n environment.vars.string(`uniqueid${i}`) ??\n (await deviceStorage.get(`uniqueid${i}`, `${i}-${Time.nowMs()}`));\n\n // Persist basic data to keep them also on restart\n await deviceStorage.set(`passcode${i}`, passcode);\n await deviceStorage.set(`discriminator${i}`, discriminator);\n await deviceStorage.set(`vendorid${i}`, vendorId);\n await deviceStorage.set(`productid${i}`, productId);\n await deviceStorage.set(`isSocket${i}`, isSocket);\n await deviceStorage.set(`uniqueid${i}`, uniqueId);\n\n devices.push({\n isSocket,\n deviceName,\n vendorName,\n passcode,\n discriminator,\n vendorId,\n productName,\n productId,\n port,\n uniqueId,\n });\n }\n\n return devices;\n}\n"],
5
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,OAAO;AAEP,SAAS,6BAA6B;AACtC,SAAS,cAAc,gBAAgB;AACvC,SAAS,mBAAmB;AAC5B,SAAS,wBAAwB;AACjC,SAAS,6BAA6B;AACtC,SAAS,UAAU,sBAAsB;AACzC,SAAS,aAAa,sBAAsB;AAC5C,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AACrB,SAAS,gBAAgB;AAEzB,sBAAsB,EAAE;AAExB,MAAM,UAAU,MAAM,iBAAiB;AACvC,SAAS,MAAM,GAAG,MAAM,QAAQ,QAAQ,OAAO;AAC3C,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,IAAI,QAAQ,GAAG;AACf,QAAM,IAAI,MAAM;AAKhB,QAAM,SAAS,MAAM,WAAW,OAAO;AAAA;AAAA,IAEnC,IAAI;AAAA;AAAA;AAAA,IAIJ,SAAS;AAAA,MACL;AAAA,IACJ;AAAA;AAAA;AAAA,IAIA,eAAe;AAAA,MACX;AAAA,MACA;AAAA,IACJ;AAAA;AAAA;AAAA,IAIA,oBAAoB;AAAA,MAChB,MAAM;AAAA,MACN,YAAY,aAAa,WAAW,sBAAsB,aAAa,iBAAiB,UAAU;AAAA,IACtG;AAAA;AAAA;AAAA,IAIA,kBAAkB;AAAA,MACd;AAAA,MACA,UAAU,SAAS,QAAQ;AAAA,MAC3B,WAAW;AAAA,MACX;AAAA,MACA,cAAc;AAAA,MACd;AAAA,MACA,cAAc,YAAY,QAAQ;AAAA,MAClC;AAAA,IACJ;AAAA,EACJ,CAAC;AAED,UAAQ;AAAA,IACJ,gBAAgB,CAAC,YAAY,IAAI,kBAAkB,QAAQ,eAAe,QAAQ,oBAAoB,aAAa;AAAA,EACvH;AAEA,QAAM,WAAW,IAAI,SAAS,WAAW,wBAAwB,kBAAkB,EAAE,IAAI,QAAQ,CAAC;AAClG,QAAM,OAAO,IAAI,QAAQ;AAOzB,WAAS,OAAO,SAAS,iBAAiB,GAAG,MAAM;AAC/C,YAAQ,IAAI,iCAAiC,CAAC,wCAAwC;AAAA,EAC1F,CAAC;AAED,WAAS,OAAO,SAAS,gBAAgB,GAAG,MAAM;AAC9C,YAAQ,IAAI,kCAAkC,CAAC,KAAK;AAAA,EACxD,CAAC;AAED,WAAS,OAAO,MAAM,aAAa,GAAG,WAAS;AAC3C,mBAAe,QAAQ,KAAK,CAAC,KAAK,MAAM,CAAC,EAAE;AAC3C,YAAQ,IAAI,SAAS,CAAC,WAAW,QAAQ,OAAO,KAAK,EAAE;AAAA,EAC3D,CAAC;AAKD,cAAY,eAAe,YAAY,MAAM,CAAC;AAE9C,UAAQ,IAAI,8BAA8B;AAC1C,UAAQ,IAAI,sBAAsB,CAAC,YAAY,IAAI,GAAG;AACtD,UAAQ,IAAI,8BAA8B;AAO1C,QAAM,OAAO,YAAY;AAC7B;AASA,SAAS,eAAe,iBAAyB;AAC7C,QAAM,SAAS,YAAY,QAAQ,KAAK,OAAO,eAAe;AAC9D,MAAI,WAAW;AAAW,WAAO;AACjC,UAAQ,IAAI,GAAG,eAAe,KAAK,SAAS,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE;AACjF;AAEA,eAAe,mBAAmB;AAC9B,QAAM,cAAc,YAAY;AAEhC,QAAM,iBAAiB,YAAY,IAAI,cAAc;AACrD,UAAQ,IAAI,qBAAqB,eAAe,QAAQ,cAAc;AACtE,UAAQ;AAAA,IACJ;AAAA,EACJ;AACA,QAAM,iBAAiB,MAAM,eAAe,KAAK,QAAQ,GAAG,cAAc,MAAM;AAEhF,MAAI,kBAAkB;AACtB,MAAI,uBAAuB;AAC3B,MAAI,cAAc;AAElB,QAAMA,WAAU,CAAC;AACjB,QAAM,aAAa,YAAY,KAAK,OAAO,KAAK,KAAK;AACrD,WAAS,IAAI,GAAG,KAAK,YAAY,KAAK;AAClC,UAAM,WAAW,MAAM,cAAc,IAAI,WAAW,CAAC,IAAI,YAAY,KAAK,OAAO,OAAO,CAAC,EAAE,MAAM,QAAQ;AACzG,QAAI,MAAM,cAAc,IAAI,WAAW,CAAC,EAAE,GAAG;AACzC,cAAQ,IAAI,eAAe,WAAW,WAAW,OAAO,iDAAiD;AAAA,IAC7G;AACA,UAAM,aAAa,UAAU,YAAY,KAAK,OAAO,OAAO,CAAC,EAAE,KAAK,OAAO,WAAW,CAAC;AACvF,UAAM,aAAa;AACnB,UAAM,WACF,YAAY,KAAK,OAAO,WAAW,CAAC,EAAE,KAAM,MAAM,cAAc,IAAI,WAAW,CAAC,IAAI,iBAAiB;AACzG,UAAM,gBACF,YAAY,KAAK,OAAO,gBAAgB,CAAC,EAAE,KAC1C,MAAM,cAAc,IAAI,gBAAgB,CAAC,IAAI,sBAAsB;AAExE,UAAM,WAAW,YAAY,KAAK,OAAO,WAAW,CAAC,EAAE,KAAM,MAAM,cAAc,IAAI,WAAW,CAAC,IAAI,KAAM;AAC3G,UAAM,cAAc,4BAA4B,CAAC;AACjD,UAAM,YACF,YAAY,KAAK,OAAO,YAAY,CAAC,EAAE,KAAM,MAAM,cAAc,IAAI,YAAY,CAAC,IAAI,KAAM;AAEhG,UAAM,OAAO,YAAY,KAAK,OAAO,OAAO,CAAC,EAAE,KAAK;AAEpD,UAAM,WACF,YAAY,KAAK,OAAO,WAAW,CAAC,EAAE,KACrC,MAAM,cAAc,IAAI,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE;AAGnE,UAAM,cAAc,IAAI,WAAW,CAAC,IAAI,QAAQ;AAChD,UAAM,cAAc,IAAI,gBAAgB,CAAC,IAAI,aAAa;AAC1D,UAAM,cAAc,IAAI,WAAW,CAAC,IAAI,QAAQ;AAChD,UAAM,cAAc,IAAI,YAAY,CAAC,IAAI,SAAS;AAClD,UAAM,cAAc,IAAI,WAAW,CAAC,IAAI,QAAQ;AAChD,UAAM,cAAc,IAAI,WAAW,CAAC,IAAI,QAAQ;AAEhD,IAAAA,SAAQ,KAAK;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,SAAOA;AACX;",
6
6
  "names": ["devices"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@project-chip/matter-node.js-examples",
3
- "version": "0.8.0",
3
+ "version": "0.8.1-alpha.0-20240403-811441fb",
4
4
  "description": "CLI/Reference implementation scripts for Matter protocol for node.js",
5
5
  "keywords": [
6
6
  "iot",
@@ -64,10 +64,10 @@
64
64
  "typescript": "~5.4.3"
65
65
  },
66
66
  "dependencies": {
67
- "@project-chip/matter-node-ble.js": "0.8.0",
68
- "@project-chip/matter-node.js": "0.8.0",
69
- "@project-chip/matter.js": "0.8.0",
70
- "@project-chip/matter.js-tools": "0.8.0"
67
+ "@project-chip/matter-node-ble.js": "0.8.1-alpha.0-20240403-811441fb",
68
+ "@project-chip/matter-node.js": "0.8.1-alpha.0-20240403-811441fb",
69
+ "@project-chip/matter.js": "0.8.1-alpha.0-20240403-811441fb",
70
+ "@project-chip/matter.js-tools": "0.8.1-alpha.0-20240403-811441fb"
71
71
  },
72
72
  "engines": {
73
73
  "_comment": "For Crypto.hkdf support",
@@ -83,5 +83,5 @@
83
83
  "publishConfig": {
84
84
  "access": "public"
85
85
  },
86
- "gitHead": "1892ef921e0931c3f749ba8e151d69b376bb2b02"
86
+ "gitHead": "cb01f664114471e7060b76f04fe063de9c2a7e8c"
87
87
  }
@@ -115,21 +115,17 @@ for (let idx = 0; idx < isSocket.length; idx++) {
115
115
  await aggregator.add(endpoint);
116
116
 
117
117
  /**
118
- * Register state change handlers of the endpoint for identify and onoff states to react to the commands.
118
+ * Register state change handlers and events of the endpoint for identify and onoff states to react to the commands.
119
119
  *
120
120
  * If the code in these change handlers fail then the change is also rolled back and not executed and an error is
121
121
  * reported back to the controller.
122
122
  */
123
- let isIdentifying = false;
124
- endpoint.events.identify.identifyTime$Change.on(value => {
125
- // identifyTime is set when an identify commandf is called and then decreased every second while indenitfy logic runs.
126
- if (value > 0 && !isIdentifying) {
127
- isIdentifying = true;
128
- console.log(`${name}: Run identify logic, ideally blink a light every 0.5s ...`);
129
- } else if (value === 0) {
130
- isIdentifying = false;
131
- console.log(`${name}: Stop identify logic ...`);
132
- }
123
+ endpoint.events.identify.startIdentifying.on(() => {
124
+ console.log(`Run identify logic for ${name}, ideally blink a light every 0.5s ...`);
125
+ });
126
+
127
+ endpoint.events.identify.stopIdentifying.on(() => {
128
+ console.log(`Stop identify logic for ${name} ...`);
133
129
  });
134
130
 
135
131
  endpoint.events.onOff.onOff$Change.on(value => {
@@ -97,16 +97,12 @@ for (let idx = 0; idx < isSocket.length; idx++) {
97
97
  * If the code in these change handlers fail then the change is also rolled back and not executed and an error is
98
98
  * reported back to the controller.
99
99
  */
100
- let isIdentifying = false;
101
- endpoint.events.identify.identifyTime$Change.on(value => {
102
- // identifyTime is set when an identify command is called and then decreased every second while indentify logic runs.
103
- if (value > 0 && !isIdentifying) {
104
- isIdentifying = true;
105
- console.log(`OnOff ${i}: Run identify logic, ideally blink a light every 0.5s ...`);
106
- } else if (value === 0) {
107
- isIdentifying = false;
108
- console.log(`OnOff ${i}: Stop identify logic ...`);
109
- }
100
+ endpoint.events.identify.startIdentifying.on(() => {
101
+ console.log(`Run identify logic for sub device ${i}, ideally blink a light every 0.5s ...`);
102
+ });
103
+
104
+ endpoint.events.identify.stopIdentifying.on(() => {
105
+ console.log(`Stop identify logic for sub device ${i}...`);
110
106
  });
111
107
 
112
108
  endpoint.events.onOff.onOff$Change.on(value => {
@@ -96,20 +96,16 @@ async function main() {
96
96
  await server.add(endpoint);
97
97
 
98
98
  /**
99
- * Register state change handlers of the node for identify and onoff states to react to the commands.
99
+ * Register state change handlers and events of the node for identify and onoff states to react to the commands.
100
100
  * If the code in these change handlers fail then the change is also rolled back and not executed and an error is
101
101
  * reported back to the controller.
102
102
  */
103
- let isIdentifying = false;
104
- endpoint.events.identify.identifyTime$Change.on(value => {
105
- // identifyTime is set when an identify command is called and then decreased every second while indentify logic runs.
106
- if (value > 0 && !isIdentifying) {
107
- isIdentifying = true;
108
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
109
- } else if (value === 0) {
110
- isIdentifying = false;
111
- console.log(`Stop identify logic ...`);
112
- }
103
+ endpoint.events.identify.startIdentifying.on(() => {
104
+ console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
105
+ });
106
+
107
+ endpoint.events.identify.stopIdentifying.on(() => {
108
+ console.log(`Stop identify logic ...`);
113
109
  });
114
110
 
115
111
  endpoint.events.onOff.onOff$Change.on(value => {
@@ -360,15 +360,12 @@ server.events.sessions.subscriptionsChanged.on(session => {
360
360
  });
361
361
 
362
362
  // React on a change of identificationTime to do Identify stuff for the own device
363
- let isIdentifying = false;
364
- endpoint.events.identify.identifyTime$Change.on(value => {
365
- if (value > 0 && !isIdentifying) {
366
- isIdentifying = true;
367
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
368
- } else if (value === 0) {
369
- isIdentifying = false;
370
- console.log(`Stop identify logic ...`);
371
- }
363
+ endpoint.events.identify.startIdentifying.on(() => {
364
+ console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
365
+ });
366
+
367
+ endpoint.events.identify.stopIdentifying.on(() => {
368
+ console.log(`Stop identify logic ...`);
372
369
  });
373
370
 
374
371
  // Our device is now built and we can bring the node online.
@@ -39,7 +39,7 @@ class RollerShade extends LiftingWindowCoveringServer {
39
39
  }
40
40
 
41
41
  override async initialize() {
42
- this.reactTo(this.events.targetPositionLiftPercent100ths$Change, this.writeTargetToMotor);
42
+ this.reactTo(this.events.targetPositionLiftPercent100ths$Change, this.writeTargetToMotor, { offline: true });
43
43
 
44
44
  await this.readTargetFromMotor();
45
45
  if (this.targetPos === null) {
@@ -99,16 +99,12 @@ for (let idx = 1; idx < devices.length; idx++) {
99
99
  * If the code in these change handlers fail then the change is also rolled back and not executed and an error is
100
100
  * reported back to the controller.
101
101
  */
102
- let isIdentifying = false;
103
- endpoint.events.identify.identifyTime$Change.on(value => {
104
- // identifyTime is set when an identify commandf is called and then decreased every second while indenitfy logic runs.
105
- if (value > 0 && !isIdentifying) {
106
- isIdentifying = true;
107
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
108
- } else if (value === 0) {
109
- isIdentifying = false;
110
- console.log(`Stop identify logic ...`);
111
- }
102
+ endpoint.events.identify.startIdentifying.on(() => {
103
+ console.log(`Run identify logic for device ${i}, ideally blink a light every 0.5s ...`);
104
+ });
105
+
106
+ endpoint.events.identify.stopIdentifying.on(() => {
107
+ console.log(`Stop identify logic for device ${i}...`);
112
108
  });
113
109
 
114
110
  endpoint.events.onOff.onOff$Change.on(value => {