Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement missing features and models in javascript client #803

Merged
merged 4 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 77 additions & 22 deletions dashboard/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import { Connection } from "./connection";
import { InvalidServerVersion } from "./exceptions";
import {
APICommands,
CommissionableNodeData,
CommissioningParameters,
ErrorResultMessage,
EventMessage,
MatterFabricData,
MatterSoftwareVersion,
NodePingResult,
SuccessResultMessage,
} from "./models/model";

Expand Down Expand Up @@ -40,60 +45,104 @@ export class MatterClient {
};
}

async commissionWithCode(code: string, networkOnly: boolean) {
console.log("TODO");
}

async commissionOnNetwork(setup_pin_code: number, ip_addr: string) {
console.log("TODO");
async commissionWithCode(code: string, networkOnly: boolean): Promise<MatterNode> {
// Commission a device using a QR Code or Manual Pairing Code.
// code: The QR Code or Manual Pairing Code for device commissioning.
// network_only: If True, restricts device discovery to network only.
// Returns: The NodeInfo of the commissioned device.
return await this.sendCommand("commission_with_code", 0, { code: code, network_only: networkOnly }) as MatterNode;
}

async setWifiCredentials(ssid: string, credentials: string) {
console.log("TODO");
// Set WiFi credentials for commissioning to a (new) device.
await this.sendCommand("set_wifi_credentials", 0, { ssid, credentials })
}

async setThreadOperationalDataset(dataset: string) {
console.log("TODO");
// Set Thread Operational dataset in the stack.
await this.sendCommand("set_thread_dataset", 0, { dataset })
}

async openCommissioningWindow(
nodeId: number,
timeout = 300,
iteration = 1000,
option = 1,
distriminator: number | undefined = undefined
) {
console.log("TODO");
timeout?: number,
iteration?: number,
option?: number,
distriminator?: number
): Promise<CommissioningParameters> {
// Open a commissioning window to commission a device present on this controller to another.
// Returns code to use as discriminator.
return await this.sendCommand("open_commissioning_window", 0, { node_id: nodeId, timeout, iteration, option, distriminator }) as CommissioningParameters;
}

async discoverCommissionableNodes(): Promise<CommissionableNodeData[]> {
// Discover Commissionable Nodes (discovered on BLE or mDNS).
return await this.sendCommand("discover_commissionable_nodes", 0, {}) as CommissionableNodeData[];
}

async discoverCommissionableNodes() {
console.log("TODO");
async getMatterFabrics(nodeId: number): Promise<MatterFabricData[]> {
// Get Matter fabrics from a device.
// Returns a list of MatterFabricData objects.
return await this.sendCommand("get_matter_fabrics", 3, {}) as MatterFabricData[];
}

async getMatterFabrics(nodeId: number) {
console.log("TODO");
async removeMatterFabric(nodeId: number, fabricIndex: number) {
// Remove a Matter fabric from a device.
await this.sendCommand("remove_matter_fabric", 3, { node_id: nodeId, fabric_index: fabricIndex });
}

async removeMatterFabric(nodeId: number, fabricId: number) {
console.log("TODO");
async pingNode(nodeId: number): Promise<NodePingResult> {
// Ping node on the currently known IP-address(es).
return await this.sendCommand("ping_node", 0, { node_id: nodeId }) as NodePingResult;
}

async pingNode(nodeId: number) {
await this.sendCommand("ping_node", 0, { node_id: nodeId });
async getNodeIPAddresses(nodeId: number, preferCache?: boolean, scoped?: boolean): Promise<string[]> {
// Return the currently known (scoped) IP-address(es).
return await this.sendCommand("get_node_ip_addresses", 8, { node_id: nodeId, prefer_cache: preferCache, scoped: scoped }) as string[];
}

async removeNode(nodeId: number) {
// Remove a Matter node/device from the fabric.
await this.sendCommand("remove_node", 0, { node_id: nodeId });
}

async interviewNode(nodeId: number) {
// Interview a node.
await this.sendCommand("interview_node", 0, { node_id: nodeId });
}

async importTestNode(dump: string) {
// Import test node(s) from a HA or Matter server diagnostics dump.
await this.sendCommand("import_test_node", 0, { dump });
}

async readAttribute(nodeId: number, attributePath: string | string[]): Promise<Record<string, any>> {
// Read one or more attribute(s) on a node by specifying an attributepath.
return await this.sendCommand("read_attribute", 0, { node_id: nodeId, attribute_path: attributePath });
}

async writeAttribute(nodeId: number, attributePath: string, value: any) {
// Write an attribute(value) on a target node.
await this.sendCommand("write_attribute", 0, { node_id: nodeId, attribute_path: attributePath, value: value });
}

async checkNodeUpdate(nodeId: number): Promise<MatterSoftwareVersion | null> {
// Check if there is an update for a particular node.
// Reads the current software version and checks the DCL if there is an update
// available. If there is an update available, the command returns the version
// information of the latest update available.
return await this.sendCommand("check_node_update", 10, { node_id: nodeId });
}

async updateNode(nodeId: number, softwareVersion: number | string) {
// Update a node to a new software version.
// This command checks if the requested software version is indeed still available
// and if so, it will start the update process. The update process will be handled
// by the built-in OTA provider. The OTA provider will download the update and
// notify the node about the new update.
await this.sendCommand("update_node", 10, { node_id: nodeId, software_version: softwareVersion });
}

async sendCommand<T extends keyof APICommands>(
command: T,
require_schema: number | undefined = undefined,
Expand Down Expand Up @@ -218,6 +267,12 @@ export class MatterClient {
this.fireEvent("nodes_changed");
return;
}

if (event.event === "server_info_updated") {
this.connection.serverInfo = event.data;
this.fireEvent("server_info_updated");
return;
}
}

private fireEvent(event: string, data?: any) {
Expand Down
87 changes: 85 additions & 2 deletions dashboard/src/client/models/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,33 @@ export interface APICommands {
response: {};
};
import_test_node: {
requestArgs: { dump: string; };
requestArgs: {};
response: null;
};
get_node_ip_addresses: {
requestArgs: {};
response: {};
};
check_node_update: {
requestArgs: {};
response: MatterSoftwareVersion | null;
};
update_node: {
requestArgs: {};
response: MatterSoftwareVersion | null;
};
discover_commissionable_nodes: {
requestArgs: {};
response: {};
};
get_matter_fabrics: {
requestArgs: {};
response: {};
};
remove_matter_fabric: {
requestArgs: {};
response: {};
};
}

export interface CommandMessage {
Expand All @@ -97,6 +121,7 @@ export interface ServerInfoMessage {
sdk_version: string;
wifi_credentials_set: boolean;
thread_credentials_set: boolean;
bluetooth_enabled: boolean;
}

interface ServerEventNodeAdded {
Expand Down Expand Up @@ -131,8 +156,12 @@ interface ServerEventEndpointRemoved {
event: "endpoint_removed";
data: {};
}
interface ServerEvenInfoUpdated {
event: "server_info_updated";
data: ServerInfoMessage;
}

export type EventMessage = ServerEventNodeAdded | ServerEventNodeUpdated | ServerEventNodeRemoved | ServerEventNodeEvent | ServerEventAttributeUpdated | ServerEventServerShutdown | ServerEventEndpointAdded | ServerEventEndpointRemoved
export type EventMessage = ServerEventNodeAdded | ServerEventNodeUpdated | ServerEventNodeRemoved | ServerEventNodeEvent | ServerEventAttributeUpdated | ServerEventServerShutdown | ServerEventEndpointAdded | ServerEventEndpointRemoved | ServerEvenInfoUpdated


export interface ResultMessageBase {
Expand All @@ -155,4 +184,58 @@ export interface WebSocketConfig {
path: string;
}

export enum UpdateSource {
MAIN_NET_DCL = "main-net-dcl",
TEST_NET_DCL = "test-net-dcl",
LOCAL = "local"
}

export interface MatterSoftwareVersion {
vid: number
pid: number
software_version: number
software_version_string: string
firmware_information?: string
min_applicable_software_version: number
max_applicable_software_version: number
release_notes_url?: string
update_source: UpdateSource
}

export interface CommissioningParameters {
setup_pin_code: number
setup_manual_code: string
setup_qr_code: string
}

export interface CommissionableNodeData {
instance_name?: string
host_name?: string
port?: number
long_discriminator?: number
vendor_id?: number
product_id?: number
commissioning_mode?: number
device_type?: number
device_name?: string
pairing_instruction?: string
pairing_hint?: number
mrp_retry_interval_idle?: number
mrp_retry_interval_active?: number
supports_tcp?: boolean
addresses?: string[]
rotating_id?: string
}

export interface MatterFabricData {
fabric_id?: number
vendor_id?: number
fabric_index?: number
fabric_label?: string
vendor_name?: string
}



export type NotificationType = "success" | "info" | "warning" | "error";
export type NodePingResult = Record<string, boolean>;
1 change: 1 addition & 0 deletions matter_server/common/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class EventType(Enum):
NODE_EVENT = "node_event"
ATTRIBUTE_UPDATED = "attribute_updated"
SERVER_SHUTDOWN = "server_shutdown"
SERVER_INFO_UPDATED = "server_info_updated"
ENDPOINT_ADDED = "endpoint_added"
ENDPOINT_REMOVED = "endpoint_removed"

Expand Down
2 changes: 2 additions & 0 deletions matter_server/server/device_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,13 +429,15 @@ async def set_wifi_credentials(self, ssid: str, credentials: str) -> None:

await self._chip_device_controller.set_wifi_credentials(ssid, credentials)
self._wifi_credentials_set = True
self.server.signal_event(EventType.SERVER_INFO_UPDATED, self.server.get_info())

@api_command(APICommand.SET_THREAD_DATASET)
async def set_thread_operational_dataset(self, dataset: str) -> None:
"""Set Thread Operational dataset in the stack."""

await self._chip_device_controller.set_thread_operational_dataset(dataset)
self._thread_credentials_set = True
self.server.signal_event(EventType.SERVER_INFO_UPDATED, self.server.get_info())

@api_command(APICommand.OPEN_COMMISSIONING_WINDOW)
async def open_commissioning_window(
Expand Down
Loading