Skip to content

Commit

Permalink
Working on controller
Browse files Browse the repository at this point in the history
  • Loading branch information
GermanBluefox committed Nov 13, 2023
1 parent eb70e65 commit b207bd2
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 117 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
- fake delete (so the real deletion will be done in backend with factory reset of device)

## Changelog
### 0.1.9 (2023-11-12)
### **WORK IN PROGRESS**
* (bluefox) Implemented the factory reset and re-announcing

### 0.1.2 (2023-10-25)
Expand Down
41 changes: 25 additions & 16 deletions src-admin/src/Tabs/Controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class Controller extends React.Component {
camera: '',
hideVideo: false,
nodes: {},
states: {},
openedNodes,
};

Expand Down Expand Up @@ -152,10 +153,15 @@ class Controller extends React.Component {
.then(() => this.props.socket.subscribeObject(`matter.${this.props.instance}.controller.*`, this.onObjectChange)
.catch(e => window.alert(`Cannot subscribe: ${e}`)))
.then(() => this.props.socket.subscribeState(`matter.${this.props.instance}.controller.*`, this.onStateChange)
.catch(e => window.alert(`Cannot subscribe: ${e}`)));
.catch(e => {
window.alert(`Cannot subscribe 1: ${e}`);
}));
}

onObjectChange = (id, obj) => {
if (!this.state.nodes) {
return;
}
const nodes = JSON.parse(JSON.stringify(this.state.nodes));
if (obj) {
nodes[id] = obj;
Expand All @@ -165,15 +171,18 @@ class Controller extends React.Component {
this.setState({ nodes });
};

onStateChange(id, state) {
onStateChange = (id, state) => {
if (!this.state.states) {
return;
}
const states = JSON.parse(JSON.stringify(this.state.states));
if (state) {
states[id] = state;
} else {
delete states[id];
}
this.setState({ states });
}
};

async componentWillUnmount() {
this.props.registerMessageHandler(null);
Expand Down Expand Up @@ -322,15 +331,13 @@ class Controller extends React.Component {
{this.state.discoveryRunning ? <LinearProgress /> : null}
<Table style={{ width: '100%' }}>
<TableHead>
<TableRow>
<TableCell>
{I18n.t('Name')}
</TableCell>
<TableCell>
{I18n.t('Identifier')}
</TableCell>
<TableCell />
</TableRow>
<TableCell>
{I18n.t('Name')}
</TableCell>
<TableCell>
{I18n.t('Identifier')}
</TableCell>
<TableCell />
</TableHead>
<TableBody>
{this.state.discovered.map(device => <TableRow>
Expand Down Expand Up @@ -384,7 +391,7 @@ class Controller extends React.Component {
{icon}
{stateId.split('.').pop()}
</TableCell>
<TableCell>{this.state.states[stateId]?.val || '--'}</TableCell>
<TableCell>{this.state.states[stateId] && this.state.states[stateId].val !== null && this.state.states[stateId].val !== undefined ? this.state.states[stateId].val.toString() : '--'}</TableCell>
</TableRow>;
}

Expand Down Expand Up @@ -496,9 +503,11 @@ class Controller extends React.Component {
</div> : null}
<Table style={{ maxWidth: 600 }} size="small">
<TableHead>
<TableCell style={{ width: 0, padding: 0 }} />
<TableCell>{I18n.t('Name')}</TableCell>
<TableCell>{I18n.t('Value')}</TableCell>
<TableRow>
<TableCell style={{ width: 0, padding: 0 }} />
<TableCell>{I18n.t('Name')}</TableCell>
<TableCell>{I18n.t('Value')}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.renderNodes()}
Expand Down
15 changes: 14 additions & 1 deletion src-admin/src/components/ConfigHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,20 @@ class ConfigHandler {

// compare config with this.config
if (JSON.stringify(config.controller) !== JSON.stringify(this.config.controller)) {
const controller = await this.socket.getObject(`matter.${this.instance}.controller`);
let controller = await this.socket.getObject(`matter.${this.instance}.controller`);
if (!controller) {
controller = {
type: 'folder',
common: {
name: 'Matter controller',
},
native: {
enabled: false,
ble: false,
uuid: uuidv4(),
},
};
}
controller.native.enabled = config.controller.enabled;
this.config.controller.enabled = config.controller.enabled;
await this.socket.setObject(controller._id, controller);
Expand Down
9 changes: 8 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,14 @@ export class MatterAdapter extends utils.Adapter {
this.log.debug('Resetting');
await this.matterServer?.close();
await this.storage?.clearAll();
await this.onReady();
// clear all nodes in the controller
await this.delObjectAsync('controller', { recursive: true });

// restart adapter
const obj = await this.getForeignObjectAsync(`system.adapter.${this.namespace}`);
if (obj) {
await this.setForeignObjectAsync(obj._id, obj);
}
}

async onMessage(obj: ioBroker.Message): Promise<void> {
Expand Down
136 changes: 119 additions & 17 deletions src/matter/ControllerNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,22 @@ const IGNORE_CLUSTERS: ClusterId[] = [
0x0046 as ClusterId, // ICD Management S
];

interface Device {
clusters: Base[];
nodeId: string;
connectionStateId?: string;
connectionStatusId?: string;
}

class Controller {
private matterServer: MatterServer | undefined;
private parameters: ControllerOptions;
private commissioningServer: CommissioningServer | undefined;
private adapter: MatterAdapter;
private commissioningController: CommissioningController | null = null;
private matterNodeIds: NodeId[] = [];
private clusters: Base[] = [];
private devices: Device[] = [];
private delayedStates: { [nodeId: string]: NodeStateInformation } = {};

constructor(options: ControllerCreateOptions) {
this.adapter = options.adapter;
Expand Down Expand Up @@ -126,7 +134,18 @@ class Controller {
)}`,
);
},
stateInformationCallback: (peerNodeId: NodeId, info: NodeStateInformation) => {
stateInformationCallback: async (peerNodeId: NodeId, info: NodeStateInformation) => {
const jsonNodeId = Logger.toJSON(peerNodeId).replace(/"/g, '');
const device: Device | undefined = this.devices.find(device => device.nodeId === jsonNodeId);
if (device) {
device.connectionStateId && (await this.adapter.setStateAsync(device.connectionStateId, info === NodeStateInformation.Connected, true));
device.connectionStatusId && (await this.adapter.setStateAsync(device.connectionStatusId, info, true));
} else {
this.adapter.log.warn(`Device ${Logger.toJSON(peerNodeId)} not found`);
// delayed state
this.delayedStates[jsonNodeId] = info;
}

switch (info) {
case NodeStateInformation.Connected:
this.adapter.log.debug(`stateInformationCallback ${peerNodeId}: Node ${originalNodeId} connected`);
Expand Down Expand Up @@ -346,9 +365,12 @@ class Controller {
changed = true;
deviceObj = {
_id: id,
type: 'device',
type: 'folder',
common: {
name: nodeIdString,
statusStates: {
onlineId: 'info.connection',
},
},
native: {
nodeId: Logger.toJSON(nodeObject.nodeId),
Expand All @@ -357,6 +379,83 @@ class Controller {
await this.adapter.setObjectAsync(deviceObj._id, deviceObj);
}

const device: Device = {
nodeId: Logger.toJSON(nodeObject.nodeId),
clusters: [],
};

this.devices.push(device);

const infoId = `controller.${nodeIdString}.info`;
let infoObj = await this.adapter.getObjectAsync(infoId);
if (!infoObj) {
infoObj = {
_id: infoId,
type: 'channel',
common: {
name: 'Connection info',
},
native: {

},
};
await this.adapter.setObjectAsync(infoObj._id, infoObj);
}

const infoConnectionId = `controller.${nodeIdString}.info.connection`;
let infoConnectionObj = await this.adapter.getObjectAsync(infoConnectionId);
if (!infoConnectionObj) {
infoConnectionObj = {
_id: infoConnectionId,
type: 'state',
common: {
name: 'Connected',
role: 'indicator.connected',
type: 'boolean',
read: true,
write: false,
},
native: {

},
};
await this.adapter.setObjectAsync(infoConnectionObj._id, infoConnectionObj);
}
device.connectionStateId = infoConnectionId;

const infoStatusId = `controller.${nodeIdString}.info.status`;
let infoStatusObj = await this.adapter.getObjectAsync(infoStatusId);
if (!infoStatusObj) {
infoStatusObj = {
_id: infoStatusId,
type: 'state',
common: {
name: 'Connection status',
role: 'state',
type: 'number',
states: {
[NodeStateInformation.Connected]: 'connected',
[NodeStateInformation.Disconnected]: 'disconnected',
[NodeStateInformation.Reconnecting]: 'reconnecting',
[NodeStateInformation.WaitingForDeviceDiscovery]: 'waitingForDeviceDiscovery',
[NodeStateInformation.StructureChanged]: 'structureChanged',
},
read: true,
write: false,
},
native: {

},
};
await this.adapter.setObjectAsync(infoStatusObj._id, infoStatusObj);
}
device.connectionStatusId = infoStatusId;
if (this.delayedStates[nodeIdString] !== undefined) {
await this.adapter.setStateAsync(infoConnectionId, this.delayedStates[nodeIdString] === NodeStateInformation.Connected, true);
await this.adapter.setStateAsync(infoStatusId, this.delayedStates[nodeIdString], true);
delete this.delayedStates[nodeIdString];
}

// Example to initialize a ClusterClient and access concrete fields as API methods
// const descriptor = nodeObject.getRootClusterClient(DescriptorCluster);
// if (descriptor !== undefined) {
Expand All @@ -382,22 +481,22 @@ class Controller {
await this.adapter.setObjectAsync(deviceObj._id, deviceObj);
}

await this.endPointToIoBrokerStructure(nodeObject.nodeId, rootEndpoint, 0);
await this.endPointToIoBrokerStructure(nodeObject.nodeId, rootEndpoint, 0, [], device);
}
}

addCluster(cluster: Base | undefined) {
addCluster(device: Device, cluster: Base | undefined) {
if (cluster) {
this.clusters.push(cluster);
device.clusters.push(cluster);
}
}

async endPointToIoBrokerStructure(nodeId: NodeId, endpoint: Endpoint, level: number): Promise<void> {
async endPointToIoBrokerStructure(nodeId: NodeId, endpoint: Endpoint, level: number, path: number[], device: Device): Promise<void> {
this.adapter.log.info(`${''.padStart(level * 2)}Endpoint ${endpoint.id} (${endpoint.name}):`);
const keys = Object.keys(Factories);
for (let f = 0; f < Factories.length; f++) {
const factory = Factories[f];
this.addCluster(await factory(this.adapter, nodeId, endpoint));
if (level) {
for (let f = 0; f < Factories.length; f++) {
this.addCluster(device, await Factories[f](this.adapter, nodeId, endpoint, path));
}
}

// for (const clusterServer of endpoint.getAllClusterServers()) {
Expand All @@ -414,8 +513,10 @@ class Controller {
// }

const endpoints = endpoint.getChildEndpoints();
for (const childEndpoint of endpoints) {
await this.endPointToIoBrokerStructure(nodeId, childEndpoint, level + 1);
path.push(0);
for (let i = 0; i < endpoints.length; i++) {
path[path.length - 1] = i;
await this.endPointToIoBrokerStructure(nodeId, endpoints[i], level + 1, path, device);
}
}

Expand Down Expand Up @@ -540,12 +641,13 @@ class Controller {
}

async stop(): Promise<void> {
for (let i = 0; i < this.clusters.length; i++) {
const cluster = this.clusters[i];
await cluster.destroy();
for (let d = 0; d < this.devices.length; d++) {
for (let c = 0; c < this.devices[d].clusters.length; c++) {
await this.devices[d].clusters[c].destroy();
}
}

this.clusters = [];
this.devices = [];

if (this.commissioningController) {
this.matterServer?.removeCommissioningController(this.commissioningController);
Expand Down
Loading

0 comments on commit b207bd2

Please sign in to comment.