Merge pull request #50 from ptvoinfo/master

Some improvements
This commit is contained in:
Koen Kanters
2018-05-21 12:03:36 +02:00
committed by GitHub
5 changed files with 146 additions and 4 deletions
+58 -1
View File
@@ -6,13 +6,15 @@ const deviceMapping = require('./devices');
const zigbee2mqtt = require('./converters/zigbee2mqtt');
const mqtt2zigbee = require('./converters/mqtt2zigbee');
const homeassistant = require('./homeassistant');
const debug = require('debug')('zigbee2mqtt');
const debug = require('debug')('zigbee2mqtt:controller');
const mqttConfigRegex = new RegExp(`${settings.get().mqtt.base_topic}/bridge/config/\\w+`, 'g');
const mqttDeviceRegex = new RegExp(`${settings.get().mqtt.base_topic}/\\w+/set`, 'g');
const mqttDevicePrefixRegex = new RegExp(`${settings.get().mqtt.base_topic}/\\w+/\\w+/set`, 'g');
const issueLink = 'https://github.com/Koenkk/zigbee2mqtt/issues';
const pollInterval = 60 * 1000; // seconds * 1000.
const softResetTimeout = 3600 * 1000; // seconds * 1000.
class Controller {
constructor() {
@@ -62,10 +64,62 @@ class Controller {
logger.warn('Set `permit_join` to `false` once you joined all devices.');
this.zigbee.permitJoin(true);
}
// Start timers.
this.pollTimer(true);
this.softResetTimeout(true);
}
softResetTimeout(start) {
if (this._softResetTimer) {
clearTimeout(this._softResetTimer);
this._softResetTimer = null;
}
if (start) {
this._softResetTimer = setTimeout(() => {
this.zigbee.softReset((error) => {
if (error) {
logger.warn('Soft reset error', error);
this.zigbee.stop((error) => {
logger.warn('Zigbee stopped');
this.zigbee.start(this.handleZigbeeMessage, (error) => {
if (error) {
logger.error('Failed to restart!');
}
});
});
} else {
logger.warn('Soft resetted zigbee');
}
this.softResetTimeout(true);
});
}, softResetTimeout);
}
}
pollTimer(start) {
// Some routers need polling to prevent them from sleeping.
if (start && !this._pollTimer) {
this._pollTimer = setInterval(() => {
const devices = this.zigbee.getAllClients().filter((d) => {
const power = d.powerSource ? d.powerSource.toLowerCase().split(' ')[0] : 'unknown';
return power !== 'battery' && power !== 'unknown' && d.type === 'Router';
});
devices.forEach((d) => this.zigbee.ping(d.ieeeAddr));
}, pollInterval);
} else if (!start && this._pollTimer) {
clearTimeout(this._pollTimer);
this._pollTimer = null;
}
}
stop(callback) {
this.mqtt.disconnect();
this.pollTimer(false);
this.softResetTimeout(false);
this.zigbee.stop(callback);
}
@@ -86,6 +140,9 @@ class Controller {
}
handleZigbeeMessage(message) {
// Zigbee message receieved, reset soft reset timeout.
this.softResetTimeout(true);
debug('Recieved zigbee message with data', message.data);
if (message.type == 'devInterview') {
+39 -1
View File
@@ -312,6 +312,23 @@ const parsers = [
return {power: precisionRound(msg.data.data['presentValue'], 2)};
},
},
{
devices: ['ZNCZ02LM'],
cid: 'genBasic',
type: 'attReport',
convert: (msg) => {
if (msg.data.data['65281']) {
const data = msg.data.data['65281'];
return {
state: data['100'] === 1 ? 'ON' : 'OFF',
power: precisionRound(data['152'], 2),
voltage: precisionRound(data['150'] * 0.1, 1),
consumption: precisionRound(data['149'], 2),
temperature: precisionRound(data['3'], 2),
};
}
},
},
{
devices: ['QBKG04LM'],
cid: 'genOnOff',
@@ -343,6 +360,27 @@ const parsers = [
return {smoke: msg.data.zoneStatus === 1};
},
},
{
devices: ['CC2530.ROUTER'],
cid: 'genOnOff',
type: 'attReport',
convert: (msg) => {
return {state: msg.data.data['onOff'] === 1};
},
},
{
devices: ['CC2530.ROUTER'],
cid: 'genBinaryValue',
type: 'attReport',
convert: (msg) => {
const data = msg.data.data;
return {
description: data['description'],
type: data['inactiveText'],
rssi: data['presentValue'],
};
},
},
// Ignore parsers (these message dont need parsing).
{
@@ -357,7 +395,7 @@ const parsers = [
{
devices: [
'WXKG11LM', 'MCCGQ11LM', 'RTCGQ11LM', 'WSDCGQ11LM', 'SJCGQ11LM', 'MCCGQ01LM', 'RTCGQ01LM', 'WXKG01LM',
'WSDCGQ01LM', 'JTYJ-GD-01LM/BW',
'WSDCGQ01LM', 'JTYJ-GD-01LM/BW', 'ZNCZ02LM',
],
cid: 'genBasic',
type: 'devChange',
+8
View File
@@ -166,6 +166,14 @@ const devices = {
description: 'WeMo smart LED bulb',
supports: 'on/off, brightness',
},
// Texax Instruments
'lumi.router': {
model: 'CC2530.ROUTER',
vendor: 'Texas Instruments',
description: 'CC2530 router [link](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/)',
supports: 'state, description, type, rssi',
},
};
module.exports = devices;
+13
View File
@@ -46,6 +46,17 @@ const configurations = {
json_attributes: ['battery'],
},
},
'binary_sensor_router': {
type: 'binary_sensor',
object_id: 'router',
discovery_payload: {
payload_on: true,
payload_off: false,
value_template: '{{ value_json.state }}',
device_class: 'connectivity',
json_attributes: ['description', 'type', 'rssi'],
},
},
// Sensor
'sensor_illuminance': {
@@ -104,6 +115,7 @@ const configurations = {
unit_of_measurement: 'Watt',
icon: 'mdi:flash',
value_template: '{{ value_json.power }}',
json_attributes: ['voltage', 'temperature', 'consumption'],
},
},
'sensor_action': {
@@ -210,6 +222,7 @@ const mapping = {
'7146060PH': [configurations.light_brightness_colortemp_xy],
'F7C033': [configurations.light_brightness],
'JTYJ-GD-01LM/BW': [configurations.binary_sensor_smoke],
'CC2530.ROUTER': [configurations.binary_sensor_router],
};
// A map of all discoverd devices
+28 -2
View File
@@ -2,9 +2,13 @@ const ZShepherd = require('zigbee-shepherd');
const logger = require('./util/logger');
const settings = require('./util/settings');
const data = require('./util/data');
const debug = require('debug')('zigbee2mqtt:zigbee');
const shepherdSettings = {
net: {panId: settings.get().advanced.pan_id},
net: {
panId: settings.get().advanced.pan_id,
channelList: [settings.get().advanced.hasOwnProperty('channel') ? settings.get().advanced.channel : 11],
},
dbPath: data.joinPath('database.db'),
};
@@ -12,6 +16,7 @@ class Zigbee {
constructor() {
this.handleReady = this.handleReady.bind(this);
this.handleMessage = this.handleMessage.bind(this);
this.handleError = this.handleError.bind(this);
}
start(onMessage, callback) {
@@ -32,10 +37,15 @@ class Zigbee {
// Register callbacks.
this.shepherd.on('ready', this.handleReady);
this.shepherd.on('ind', this.handleMessage);
this.shepherd.on('error', this.handleError);
this.onMessage = onMessage;
}
softReset(callback) {
this.shepherd.reset('soft', callback);
}
stop(callback) {
this.shepherd.stop((error) => {
logger.info('zigbee-shepherd stopped');
@@ -46,9 +56,10 @@ class Zigbee {
handleReady() {
// Set all Xiaomi devices (manufId === 4151) to be online, so shepherd won't try
// to query info from devices (which would fail because they go tosleep).
// Xiaomi lumi.plug has manufId === 4447 and can be in the sleep mode too
const devices = this.getAllClients();
devices.forEach((device) => {
if (device.manufId === 4151) {
if ((device.manufId === 4151) || (device.manufId === 4447)) {
this.shepherd.find(device.ieeeAddr, 1).getDevice().update({
status: 'online',
joinTime: Math.floor(Date.now() / 1000),
@@ -59,6 +70,11 @@ class Zigbee {
logger.info('zigbee-shepherd ready');
}
handleError(message) {
// This event may appear if zigbee-shepherd cannot decode bad packets (invalid checksum).
logger.error(message);
}
permitJoin(permit) {
if (permit) {
logger.info('Zigbee: allowing new devices to join.');
@@ -77,6 +93,16 @@ class Zigbee {
return this.shepherd.list().filter((device) => device.type !== 'Coordinator');
}
ping(deviceID) {
const device = this.shepherd._findDevByAddr(deviceID);
if (device) {
// Note: checkOnline has the callback argument but does not call callback
debug(`Check online ${deviceID}`);
this.shepherd.controller.checkOnline(device);
}
}
handleMessage(message) {
if (this.onMessage) {
this.onMessage(message);