Skip to content

Instantly share code, notes, and snippets.

@Hermitter
Last active November 5, 2022 19:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Hermitter/d560e6c23763b74c7bc5c4d2b1271935 to your computer and use it in GitHub Desktop.
Save Hermitter/d560e6c23763b74c7bc5c4d2b1271935 to your computer and use it in GitHub Desktop.
For handling zigbee lights
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Set Initial Variables \\
var fs = require('fs');// File system library
var zmq = require('zeromq');// Asynchronous Messaging Framework
var matrix_io = require('matrix-protos').matrix_io;// Protocol Buffers for MATRIX function
var matrix_ip = '127.0.0.1';// Local IP
var matrix_zigbee_base_port = 40001;// Port for Zigbee driver
var networkCommands = matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkMgmtCmdTypes;// Network Command Types
var networkStatuses = matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkStatus// Network Status
var joinTimer = 60// Amount of time for Zigbee devices to join
var gateway_is_active = false;// Bool to hold Gateway CLI Tool status
// If missing, create JSON file to store Zigbee devices
if (!fs.existsSync('./devices.json')){
fs.writeFileSync('./devices.json', JSON.stringify({}, null, 2) , 'utf-8');
console.log('Creating .json file to store Zigbee devices.');
}
// Import Devices.json as an object
console.log('\nLoaded .json file with your Zigbee devices.\n');
var zigbeeDevices = JSON.parse(fs.readFileSync('./devices.json')); // Holds registered Zigbee Devices
// Store device count
var deviceCount = Object.keys(zigbeeDevices).length;
// Create driver configuration for Zigbee network
var zb_network_msg = matrix_io.malos.v1.driver.DriverConfig.create({
// Create Zigbee message
zigbeeMessage: matrix_io.malos.v1.comm.ZigBeeMsg.create({
// Set type to network management
type: matrix_io.malos.v1.comm.ZigBeeMsg.ZigBeeCmdType.NETWORK_MGMT,
// Call a network management command
networkMgmtCmd: matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.create({
// Set command to permit join
type: matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkMgmtCmdTypes.PERMIT_JOIN,
// Set timer for join period
permitJoinParams: matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.PermitJoinParams.create({time: joinTimer})
})
})
});
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// BASE PORT \\
// Create a Pusher socket
var configSocket = zmq.socket('push');
// Connect Pusher to Base port
configSocket.connect('tcp://' + matrix_ip + ':' + matrix_zigbee_base_port);
// Create driver configuration for updates/timeouts
var config = matrix_io.malos.v1.driver.DriverConfig.create({
// Update rate configuration
delayBetweenUpdates: 1.0,// 2 seconds between updates
timeoutAfterLastPing: 6.0,// Stop sending updates 6 seconds after pings.
});
// Send initial driver configuration
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(config).finish());
// Reset Gateway CLI Tool
resetGateway(
// Wait 3 seconds
setTimeout(function(){
// Request Gateway status in Data port
isGatewayActive();
}, 2000)
);
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// KEEP-ALIVE PORT \\
// Create a Pusher socket
var pingSocket = zmq.socket('push');
// Connect Pusher to Keep-alive port
pingSocket.connect('tcp://' + matrix_ip + ':' + (matrix_zigbee_base_port + 1));
// Send initial ping
pingSocket.send('');
// Send a ping every second
setInterval(function(){
pingSocket.send('');
}, 1000);
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// ERROR PORT \\
// Create a Subscriber socket
var errorSocket = zmq.socket('sub');
// Connect Subscriber to Error port
errorSocket.connect('tcp://' + matrix_ip + ':' + (matrix_zigbee_base_port + 2));
// Connect Subscriber to Error port
errorSocket.subscribe('');
// On Message
errorSocket.on('message', function(error_message){
console.log('Received Message: ' + error_message.toString('utf8'));// Log error
});
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// DATA UPDATE PORT \\
// Create a Subscriber socket
var updateSocket = zmq.socket('sub');
// Connect Subscriber to Data Update port
updateSocket.connect('tcp://' + matrix_ip + ':' + (matrix_zigbee_base_port + 3));
// Subscribe to messages
updateSocket.subscribe('');
// On Message
updateSocket.on('message', function(buffer){
var data = matrix_io.malos.v1.comm.ZigBeeMsg.decode(buffer);// Extract message
// If gateway active and devices are waiting to join
if(gateway_is_active && data.networkMgmtCmd.type === networkCommands.DISCOVERY_INFO){
// Manage Devices connecting
manageZigbeeDevices(buffer);
}
// If gateway active and network status is requested
else if(gateway_is_active && zb_network_msg.zigbeeMessage.networkMgmtCmd.type === networkCommands.NETWORK_STATUS){
// Switch Cases For Network Statuses
switch(data.networkMgmtCmd.networkStatus.type){
//* IF NO NETWORK
case networkStatuses.Status.NO_NETWORK:
console.log('No Network');
// Add (create network) to configuration
zb_network_msg.zigbeeMessage.networkMgmtCmd.type = networkCommands.CREATE_NWK;
// Send configuration
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_network_msg).finish());
break;
//* IF JOINING NETWORK
case networkStatuses.Status.JOINING_NETWORK:
console.log('Joining Network');
break;
//* IF JOINED NETWORK
case networkStatuses.Status.JOINED_NETWORK:
console.log('Joined Existing Network');
// Add (permit devices to join) in configuration
zb_network_msg.zigbeeMessage.networkMgmtCmd.type = networkCommands.PERMIT_JOIN;
// Add (set join time limit to 60 seconds) in configuration
zb_network_msg.zigbeeMessage.networkMgmtCmd.permitJoinParams.time = joinTimer;
// Send configuration
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_network_msg).finish());
// Log status
console.log('Waiting ' + joinTimer + ' seconds for devices to join.');
// Start timer to exit & save program
saveAndQuit(joinTimer);
break;
//* IF JOINED NETWORK WITH NO PARENT
case networkStatuses.Status.JOINED_NETWORK_NO_PARENT:
console.log('Joined Network With No Parent');
break;
//* IF LEAVING NETWORK
case networkStatuses.Status.LEAVING_NETWORK:
console.log('Leaving Network');
break;
}
}
// Check if Gateway tool restarted
else if(gateway_is_active === false){
gateway_is_active = true;// update boolean
// If Gateway tool is active
if(data.networkMgmtCmd.isProxyActive){
console.log('Gateway CLI Tool is active.');// Log status
// Add request for Zigbee Network Status in configuration
zb_network_msg.zigbeeMessage.networkMgmtCmd.type = networkCommands.NETWORK_STATUS;
// Send configuration
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_network_msg).finish());
}
// If Gateway Tool is down
else{
console.log('\nGateway Reset Failed. Try restarting.');// Log status
process.exit(1);// Exit application
}
}
});
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS \\
// - Restart Zigbee CLI tool called Gateway (optional, but ensures tool is running)
function resetGateway(callback) {
console.log('Resetting Gateway CLI Tool.');
// Define configuration message as Reset
zb_network_msg.zigbeeMessage.networkMgmtCmd.type = matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkMgmtCmdTypes.RESET_PROXY;
// Send configuration to Base Port
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_network_msg).finish());
// Run callback if defined
if(callback)
callback;
}
// - Ask for Gateway status through Data port
function isGatewayActive() {
// Log that connection is being tested
console.log('Checking connection with the Gateway CLI Tool.');
// Save Gateway status request to configuration
zb_network_msg.zigbeeMessage.networkMgmtCmd.type = matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkMgmtCmdTypes.IS_PROXY_ACTIVE;
// Send configuration to Base port
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_network_msg).finish());
}
// - Save & Quit program
function saveAndQuit(timer){
// Counter to count each second
var counter = 0;
// Increase counter every second
setInterval(function(){
// If counter has reached timer, exit
if(counter >= timer){
console.log('\n'+joinTimer+' seconds passed. Saving&Exiting program.');
process.exit();// exit application
}
// Else increase counter
else{
counter++;
console.log(counter);
}
},1000);
}
// - Save discovered devices
function manageZigbeeDevices(buffer){
console.log('Device(s) found!');
// Extract Data Update Port message
var data = matrix_io.malos.v1.comm.ZigBeeMsg.decode(buffer);
//Look for Zigbee devices with an ON/OFF cluster ID
// For each node
data.networkMgmtCmd.connectedNodes.map(function(nodes){
console.log(nodes);
// For each endpoint in nodes
nodes.endpoints.map(function(endpoint){
// For each cluster in endpoint
endpoint.clusters.map(function(cluster){
// For each saved device
for(device in zigbeeDevices){
// If newly discovered device was already saved
if( zigbeeDevices[device].node_id === nodes.nodeId )
return;// Exit function
}
// If cluster ID is ON/OFF
if (cluster.clusterId == 6) {
// Save device nodeId & endpointIndex to JSON file
zigbeeDevices['device_'+deviceCount] = {node_id:nodes.nodeId, endpoint_index: endpoint.endpointIndex};
// Update device count
deviceCount++;
// Update devices.json
fs.writeFile('./devices.json', JSON.stringify(zigbeeDevices, null, 2) , 'utf-8', function(){
console.log('Saved discovered device');// Log that device was saved
});
}
});
});
});
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Set Initial Variables \\
var fs = require('fs');// File system library
var zmq = require('zeromq');// Asynchronous Messaging Framework
var matrix_io = require('matrix-protos').matrix_io;// Protocol Buffers for MATRIX function
var matrix_ip = '127.0.0.1';// Local IP
var matrix_zigbee_base_port = 40001;// Port for Zigbee driver
var networkCommands = matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkMgmtCmdTypes;// Network Command Types
var networkStatuses = matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkStatus// Network Status
var gateway_is_active = false;// Bool to hold Gateway CLI Tool ON status
var gateway_is_restarting = false// Bool to hold Gateway CLI Tool ON status
// If missing, create JSON file to store Zigbee devices
if (!fs.existsSync('./devices.json')){
console.log('devices.json was not found!');
process.exit(1);
}
// Import Devices.json as an object
console.log('\nLoaded .json file with your Zigbee devices.\n');
var zigbeeDevices = JSON.parse(fs.readFileSync('./devices.json')); // Holds registered Zigbee Devices
// Create driver configuration for Zigbee network
var zb_network_msg = matrix_io.malos.v1.driver.DriverConfig.create({
zigbeeMessage: matrix_io.malos.v1.comm.ZigBeeMsg.create({
type: matrix_io.malos.v1.comm.ZigBeeMsg.ZigBeeCmdType.NETWORK_MGMT,
networkMgmtCmd: matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.create({
type: matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkMgmtCmdTypes.PERMIT_JOIN,
})
})
});
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// BASE PORT \\
// Create a Pusher socket
var configSocket = zmq.socket('push');
// Connect Pusher to Base port
configSocket.connect('tcp://' + matrix_ip + ':' + matrix_zigbee_base_port);
// Create driver configuration for updates/timeouts
var config = matrix_io.malos.v1.driver.DriverConfig.create({
// Update rate configuration
delayBetweenUpdates: 1.0,// 2 seconds between updates
timeoutAfterLastPing: 6.0,// Stop sending updates 6 seconds after last ping.
});
// Send initial driver configuration
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(config).finish());
setTimeout(isGatewayActive, 3000);
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// KEEP-ALIVE PORT \\
// Create a Pusher socket
var pingSocket = zmq.socket('push');
// Connect Pusher to Keep-alive port
pingSocket.connect('tcp://' + matrix_ip + ':' + (matrix_zigbee_base_port + 1));
// Send initial ping
pingSocket.send('');
// Send a ping every second
setInterval(function(){
pingSocket.send('');
}, 1000);
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// ERROR PORT \\
// Create a Subscriber socket
var errorSocket = zmq.socket('sub');
// Connect Subscriber to Error port
errorSocket.connect('tcp://' + matrix_ip + ':' + (matrix_zigbee_base_port + 2));
// Connect Subscriber to Error port
errorSocket.subscribe('');
// On Message
errorSocket.on('message', function(error_message){
console.log('Received Message: ' + error_message.toString('utf8'));// Log error
});
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// DATA UPDATE PORT \\
// Create a Subscriber socket
var updateSocket = zmq.socket('sub');
// Connect Subscriber to Data Update port
updateSocket.connect('tcp://' + matrix_ip + ':' + (matrix_zigbee_base_port + 3));
// Subscribe to messages
updateSocket.subscribe('');
// On Message
updateSocket.on('message', function(buffer){
var data = matrix_io.malos.v1.comm.ZigBeeMsg.decode(buffer);// Extract message
//console.log(data);
// If gateway active and network status is requested
if(gateway_is_active && zb_network_msg.zigbeeMessage.networkMgmtCmd.type === networkCommands.NETWORK_STATUS){
// Switch Cases For Network Statuses
switch(data.networkMgmtCmd.networkStatus.type){
//* IF NO NETWORK
case networkStatuses.Status.NO_NETWORK:
console.log('No Network');
process.exit(1);// Exit application
break;
//* IF JOINING NETWORK
case networkStatuses.Status.JOINING_NETWORK:
console.log('Joining Network');
break;
//* IF JOINED NETWORK
case networkStatuses.Status.JOINED_NETWORK:
console.log('Joined Existing Network\n');
sendAllToggleCommand();
break;
}
}
// Check if Gateway tool restarted
else if(gateway_is_active === false){
// If Gateway tool is active
if(data.networkMgmtCmd.isProxyActive){
gateway_is_active = true;// update boolean
console.log('Gateway CLI Tool is active.');// Log status
// Add request for Zigbee Network Status in configuration
zb_network_msg.zigbeeMessage.networkMgmtCmd.type = networkCommands.NETWORK_STATUS;
// Send configuration
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_network_msg).finish());
}
// If Gateway CLI Tool is down
else if (gateway_is_restarting === false){
gateway_is_restarting = true;// update boolean
console.log('Gateway CLI Tool Is Offline. Please wait 10 seconds for restart.');// Log status
resetGateway( setTimeout(isGatewayActive, 10000) );// Restart Gateway
}
}
});
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS \\
// - Restart Zigbee CLI tool called Gateway (optional, but ensures tool is running)
function resetGateway(callback) {
console.log('Restarting Gateway Tool.\n');
// Define configuration message as Reset
zb_network_msg.zigbeeMessage.networkMgmtCmd.type = matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkMgmtCmdTypes.RESET_PROXY;
// Send configuration to Base Port
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_network_msg).finish());
// Run callback if defined
if(callback)
callback;
}
// - Ask for Gateway status through Data port
function isGatewayActive() {
// Log that connection is being tested
console.log('Checking connection with the Gateway');
// Save Gateway status request to configuration
zb_network_msg.zigbeeMessage.networkMgmtCmd.type = matrix_io.malos.v1.comm.ZigBeeMsg.NetworkMgmtCmd.NetworkMgmtCmdTypes.IS_PROXY_ACTIVE;
// Send configuration to Base port
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_network_msg).finish());
}
// - Toggle each zigbee device on & off
function sendAllToggleCommand(){
setInterval(function(){
for(device in zigbeeDevices){
console.log('Sent message to ' + device);
var zb_toggle_msg = matrix_io.malos.v1.driver.DriverConfig.create({
zigbeeMessage: matrix_io.malos.v1.comm.ZigBeeMsg.create({
type: matrix_io.malos.v1.comm.ZigBeeMsg.ZigBeeCmdType.ZCL,
zclCmd: matrix_io.malos.v1.comm.ZigBeeMsg.ZCLCmd.create({
type: matrix_io.malos.v1.comm.ZigBeeMsg.ZCLCmd.OnOffCmd.ZCLOnOffCmdType.ON_OFF,
onoffCmd: matrix_io.malos.v1.comm.ZigBeeMsg.ZCLCmd.OnOffCmd.create({
type: matrix_io.malos.v1.comm.ZigBeeMsg.ZCLCmd.OnOffCmd.ZCLOnOffCmdType.TOGGLE
}),
nodeId: zigbeeDevices[device].node_id,
endpointIndex: zigbeeDevices[device].endpoint_index
})
})
});
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(zb_toggle_msg).finish());
}
},2000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment