forked from Koenkk/zigbee2mqtt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
171 lines (143 loc) · 4.83 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
const debug = require('debug')('xiaomi-zb2mqtt')
const util = require("util");
const perfy = require('perfy');
const ZShepherd = require('zigbee-shepherd');
const mqtt = require('mqtt')
const ArgumentParser = require('argparse').ArgumentParser;
const fs = require('fs');
const parsers = require('./parsers');
const configFile = `${__dirname}/data/config.json`
// Create configFile if does not exsist.
if (!fs.existsSync(configFile)) {
console.log(`Created config file at ${configFile}`);
console.log('Modify this config file according to your situation.');
console.log('"mqtt": the MQTT host, E.G. mqtt://192.168.1.10')
console.log('"device": location of CC2531 usb stick, E.G. /dev/ttyACM0')
console.log("")
console.log('Once finished, restart the application.');
console.log('Exiting...');
const template = {
'mqtt': 'mqtt://192.168.1.10',
'device': '/dev/ttyACM0',
'friendlyNames': {}
}
writeConfig(template);
process.exit();
}
const config = readConfig();
// Parse arguments
const parser = new ArgumentParser({
version: '1.0.0',
addHelp:true,
description: 'Xiaomi Zigbee to MQTT bridge using zigbee-shepherd'
});
parser.addArgument(
['--join'],
{
help: 'Allow new devices to join the network',
action: 'storeTrue',
}
);
const args = parser.parseArgs();
// Setup client
console.log(`Connecting to MQTT server at ${config.mqtt}`)
const client = mqtt.connect(config.mqtt)
const shepherd = new ZShepherd(
config.device,
{
net: {panId: 0x1a62},
dbPath: `${__dirname}/data/database.db`
}
);
// Register callbacks
client.on('connect', handleConnect);
shepherd.on('ready', handleReady);
shepherd.on('ind', handleMessage);
process.on('SIGINT', handleQuit);
// Start server
console.log(`Starting zigbee-shepherd with device ${config.device}`)
shepherd.start((err) => {
if (err) {
console.error('Error while starting zigbee-shepherd');
console.error(err);
} else {
console.error('zigbee-shepherd started');
}
});
// Callbacks
function handleReady() {
console.log('zigbee-shepherd ready');
const devices = shepherd.list().filter((device) => {
return device.manufId === 4151 && device.type === 'EndDevice'
});
console.log(`Currently ${devices.length} devices are joined:`);
devices.forEach((device) => {
console.log(`${device.ieeeAddr} ${device.nwkAddr} ${device.modelId}`);
});
// Set all Xiaomi devices to be online, so shepherd won't try
// to query info from devices (which would fail because they go tosleep).
devices.forEach((device) => {
shepherd.find(device.ieeeAddr, 1).getDevice().update({
status: 'online',
joinTime: Math.floor(Date.now()/1000)
});
});
// Allow or disallow new devices to join the network.
if (args.join) {
console.log('WARNING: --join parameter detected, allowing new devices to join. Remove this parameter once you added all devices.')
}
shepherd.permitJoin(args.join ? 255 : 0, (err) => {
if (err) {
console.log(err);
}
});
}
function handleConnect() {
client.publish('xiaomiZb', 'Bridge online');
}
function handleMessage(msg) {
if (msg.type !== 'attReport') {
return;
}
const device = msg.endpoints[0].device;
// Check if new device, add to config if new.
if (!config.devices[device.ieeeAddr]) {
console.log(`Detected new device: ${device.ieeeAddr} ${device.nwkAddr} ${device.modelId}`);
config.devices[device.ieeeAddr] = device.ieeeAddr;
writeConfig(config);
}
// Check if we have a parser for this type of message.
const deviceID = msg.endpoints[0].devId;
const parser = parsers.find((p) => p.supportedDevices.includes(deviceID));
if (!parser) {
console.log(`
WARNING: No parser available for deviceID: ${deviceID}
Please report on https://github.com/Koenkk/xiaomi-zb2mqtt/issues
to add support for your device`);
return;
}
// Parse the message.
const friendlyName = config.devices[device.ieeeAddr];
const payload = parser.parse(msg).toString();
const topic = `xiaomi/${friendlyName}/${parser.topic}`;
// Send the message.
console.log(`MQTT publish, topic: '${topic}', payload: '${payload}'`);
client.publish(topic, payload);
}
function handleQuit() {
shepherd.stop((err) => {
if (err) {
console.error('Error while stopping zigbee-shepherd');
} else {
console.error('zigbee-shepherd stopped')
}
process.exit();
});
}
function readConfig() {
return JSON.parse(fs.readFileSync(configFile, 'utf8'));
}
function writeConfig(content) {
const pretty = JSON.stringify(content, null, 2);
fs.writeFileSync(configFile, pretty);
}