ha-matter-bridge/matter-bridge/src/matter/Bridge.ts

150 lines
5.3 KiB
TypeScript

import {
CommissioningServer,
MatterServer,
} from '@project-chip/matter-node.js';
import {
Aggregator,
ComposedDevice,
Device,
DeviceTypes,
} from '@project-chip/matter-node.js/device';
import { Logger } from '@project-chip/matter-node.js/log';
import { StorageManager } from '@project-chip/matter-node.js/storage';
import { getIntParameter, getParameter } from '../utils/utils';
import { Time } from '@project-chip/matter-node.js/time';
import { VendorId } from '@project-chip/matter-node.js/datatype';
import { QrCode } from '@project-chip/matter-node.js/schema';
import {
AttributeInitialValues,
BridgedDeviceBasicInformationCluster,
} from '@project-chip/matter-node.js/cluster';
export class Bridge {
private static readonly deviceName =
getParameter('name') || 'Matter Bridge';
private static readonly deviceType = DeviceTypes.AGGREGATOR.code;
private static readonly vendorName = getParameter('vendor') || 'Jatus';
private static readonly productName = 'HomeAssistant';
private static readonly port = getIntParameter('port') ?? 5540;
private ready = false;
private matterServer: MatterServer;
private static instace: Bridge;
private logger = new Logger('bridge');
private storageManager: StorageManager;
private aggregator: Aggregator;
this: any;
commissioningServer: CommissioningServer;
private constructor(
matterServer: MatterServer,
storageManager: StorageManager
) {
this.matterServer = matterServer;
this.storageManager = storageManager;
this.aggregator = new Aggregator();
}
public static getInstance(
matterServer: MatterServer,
storageManager: StorageManager
): Bridge {
if (!Bridge.instace) {
this.instace = new Bridge(matterServer, storageManager);
}
return Bridge.instace;
}
private async setupContextAndCommissioningServer(): Promise<CommissioningServer> {
this.logger.info('setting up context');
await this.storageManager.initialize();
const deviceContextStorage =
this.storageManager.createContext('Bridge-Device');
const passcode =
getIntParameter('passcode') ??
deviceContextStorage.get('passcode', 20202021);
const discriminator =
getIntParameter('discriminator') ??
deviceContextStorage.get('discriminator', 3840);
const vendorId =
getIntParameter('vendorid') ??
deviceContextStorage.get('vendorid', 0xfff1);
const productId =
getIntParameter('productid') ??
deviceContextStorage.get('productid', 0x8000);
const uniqueId =
getIntParameter('uniqueid') ??
deviceContextStorage.get('uniqueid', Time.nowMs());
deviceContextStorage.set('passcode', passcode);
deviceContextStorage.set('discriminator', discriminator);
deviceContextStorage.set('vendorid', vendorId);
deviceContextStorage.set('productid', productId);
deviceContextStorage.set('uniqueid', uniqueId);
const commissioningServer = new CommissioningServer({
port: Bridge.port,
deviceName: Bridge.deviceName,
deviceType: Bridge.deviceType,
passcode,
discriminator,
basicInformation: {
vendorName: Bridge.vendorName,
vendorId: VendorId(vendorId),
nodeLabel: Bridge.productName,
productName: Bridge.productName,
productLabel: Bridge.productName,
productId,
serialNumber: `node-matter-${uniqueId}`,
},
});
return commissioningServer;
}
addDevice(
device: Device | ComposedDevice,
bridgedBasicInformation?: AttributeInitialValues<
typeof BridgedDeviceBasicInformationCluster.attributes
>
) {
if (!this.commissioningServer.isCommissioned()) {
this.logger.warn('System not initialized, may cause crashes');
}
this.this.aggregator.addBridgedDevice(device, bridgedBasicInformation);
}
async start() {
this.logger.info('Starting...');
this.commissioningServer =
await this.setupContextAndCommissioningServer();
this.commissioningServer.addDevice(this.aggregator);
this.matterServer.addCommissioningServer(this.commissioningServer);
await this.matterServer.start();
this.logger.info('Listening');
if (!this.commissioningServer.isCommissioned()) {
const pairingData = this.commissioningServer.getPairingCode();
const { qrPairingCode, manualPairingCode } = pairingData;
console.log(QrCode.get(qrPairingCode));
this.logger.info(
`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`
);
this.logger.info(`Manual pairing code: ${manualPairingCode}`);
} else {
this.logger.info(
'Device is already commissioned. Waiting for controllers to connect ...'
);
}
}
async stop() {
this.matterServer.close();
this.storageManager
.close()
.then(() => process.exit(0))
.catch((err) => this.logger.error(err));
}
}