forked from Koenkk/zigbee2mqtt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
156 lines (132 loc) · 4.65 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
const debug = require('debug')('xiaomi-zb2mqtt')
const util = require("util");
const ZShepherd = require('zigbee-shepherd');
const mqtt = require('mqtt')
const fs = require('fs');
const parsers = require('./parsers');
const config = require('yaml-config');
const configFile = `${__dirname}/data/configuration.yaml`
const settings = config.readConfig(configFile, 'user');
// Create empty device array if not set yet.
if (!settings.devices) {
settings.devices = {};
writeConfig();
}
// Setup client
console.log(`Connecting to MQTT server at ${settings.mqtt.server}`)
const client = mqtt.connect(settings.mqtt.server)
const shepherd = new ZShepherd(
settings.serial.port,
{
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 ${settings.serial.port}`)
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 (settings.allowJoin) {
console.log(`
WARNING: allowJoin set to true in configuration.yaml.
Allowing new devices to join.
Remove this parameter once you joined all devices.
`);
}
shepherd.permitJoin(settings.allowJoin ? 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 (!settings.devices[device.ieeeAddr]) {
console.log(`Detected new device: ${device.ieeeAddr} ${device.nwkAddr} ${device.modelId}`);
settings.devices[device.ieeeAddr] = {
friendly_name: device.ieeeAddr
};
writeConfig();
}
// Check if we have a parser for this type of message.
const modelID = msg.endpoints[0].device.modelId;
const deviceID = msg.endpoints[0].devId;
const cid = msg.data.cid;
const parser = parsers.find((p) => {
const device = p.supportedDevices.find((device) => device[0] === deviceID && device[1] === modelID);
return device && p.cid === cid;
});
if (!parser) {
console.log(`
WARNING: No parser available for (${deviceID}, '${modelID}') for cid: ${cid}
Please report on https://github.com/Koenkk/xiaomi-zb2mqtt/issues
to add support for your device`);
return;
}
// Parse generic information from message.
const friendlyName = settings.devices[device.ieeeAddr].friendly_name;
const topic = `${settings.mqtt.base_topic}/${friendlyName}/${parser.topic}`;
// Define publih function.
const publish = (payload) => {
console.log(`MQTT publish, topic: '${topic}', payload: '${payload}'`);
client.publish(topic, payload.toString());
}
// Get payload for the message.
// - If a payload is returned publish it to the MQTT broker
// - If NO payload is returned do nothing. This is for non-standard behaviour
// for e.g. click switches where we need to count number of clicks and detect long presses.
const payload = parser.parse(msg, publish);
if (payload) {
publish(payload);
}
}
function handleQuit() {
shepherd.stop((err) => {
if (err) {
console.error('Error while stopping zigbee-shepherd');
} else {
console.error('zigbee-shepherd stopped')
}
process.exit();
});
}
function writeConfig() {
config.updateConfig(settings, configFile, 'user');
}