Compare commits

...
53 Commits
Author SHA1 Message Date
Koenkk 7d49e136a6 0.1.5 2018-09-19 21:00:03 +02:00
Koenkk 0c1dba7208 Fix functional command. #386 2018-09-19 20:59:30 +02:00
Koenkk 63f4f681c4 0.1.4 2018-09-19 18:59:52 +02:00
Unknown 1afbe05318 Update zigbee-shepherd-converters. 2018-09-18 22:24:17 +02:00
Plácido Revilla 8376b7c5f6 Add support for homeassistant discovery of E11-N1EA (#379) 2018-09-18 18:07:33 +02:00
Unknown b71a9920de Update zcl-packet. #373 2018-09-18 18:03:27 +02:00
Unknown 2fd59cb7ef Remove log_directory_timestamp option, implement default settings, no : in timestamp. #356 #381 2018-09-18 17:51:34 +02:00
Zhong Jianxin 60e72c612c Allow no timestamp in log directory (#356)
* Allow no timestamp in log directory

* Update log_directory_timestamp option
2018-09-17 22:55:17 +02:00
Koen Kanters fbbc1fad73 Merge pull request #371 from dzungpv/dev
Fix foundation error from #8433571
2018-09-14 08:34:58 +02:00
Koen Kanters d5de918247 Revert 2018-09-14 08:33:28 +02:00
Koen Kanters f916ec5f4c Update foundation publish 2018-09-14 08:31:11 +02:00
Viet Dzung 469a01ebb6 Fix foundation error from #8433571 2018-09-14 10:01:07 +07:00
Koenkk 6ede5a373e Update zigbee-shepherd/zcl-packet. 2018-09-12 22:16:59 +02:00
Koenkk 6e1af542e5 Update zigbee-shepherd-converter. 2018-09-11 22:04:37 +02:00
Koen Kanters 53051e9192 Merge pull request #351 from lolorc/linkquality0
don't ignore linkquality when its value is 0
2018-09-11 21:42:03 +02:00
Koenkk 542a5f1564 Update zigbee-shepherd-converters. #355 2018-09-11 21:41:24 +02:00
Koen Kanters b82f0e46aa Use hasOwnProperty for linkquality check. https://stackoverflow.com/questions/13632999/if-key-in-object-or-ifobject-hasownpropertykey 2018-09-11 21:38:01 +02:00
Koen Kanters f0f2dc847b Merge pull request #355 from dzungpv/dev
Support Foundation Command for use in zigbee-shepherd converter
2018-09-11 21:34:25 +02:00
Koenkk 8433571b1e Refactor multiple foundation. 2018-09-11 21:28:30 +02:00
Koenkk 2141d670bf Update dependencies. 2018-09-11 18:01:48 +02:00
Viet Dzung fccb4de565 Fix Lint error 2018-09-11 14:28:04 +07:00
Viet Dzung 236afaacaf Support Foundation Command for use in zigbee-shepherd converter https://github.com/zigbeer/zcl-packet/wiki/6.-Appendix#FoundCmdTbl 2018-09-11 13:59:49 +07:00
Koenkk f463ca68a5 Improve zigbee message debug logging. 2018-09-10 18:06:29 +02:00
Laurent 7502ba5312 don't ignore linkquality when its value is 0 2018-09-09 19:28:38 +02:00
Koen Kanters c05b70b30b Merge pull request #325 from sebastianheierhoff/master
Fix issue #306: Sending config msg works only with default topic
2018-09-03 16:24:23 +02:00
sebastianheierhoff c22f8b36ba Fix issue #306: Sending config msg works only with default topic 2018-08-31 12:34:59 +02:00
Koenkk 7276d116c2 Update dependencies. 2018-08-30 18:06:52 +02:00
Koen Kanters 1b7549dd73 Merge pull request #316 from sebastianheierhoff/master
Fix issue #229: router devices can't be managed by zigbee2mqtt
2018-08-30 17:59:22 +02:00
Koen Kanters 7e4fff8454 Merge pull request #313 from TheCellMC/master
Add support for Philips Hue motion sensor
2018-08-30 17:53:09 +02:00
sebastianheierhoff ad43d61f28 Fix issue #229: router devices can't be managed by zigbee2mqtt 2018-08-29 19:22:36 +02:00
sebastianheierhoff ed5c52654f Fix issue #229: router devices can't be managed by zigbee2mqtt 2018-08-29 19:19:54 +02:00
sebastianheierhoff 4f1b521bee Fix issue #229: router devices can't be managed by zigbee2mqtt 2018-08-29 18:49:01 +02:00
TheCellMC a46f06a312 Update homeassistant.js 2018-08-29 09:14:20 +02:00
TheCellMC 6311dfb0f1 Update homeassistant.js 2018-08-29 09:11:41 +02:00
TheCellMC ee82a885f7 Update homeassistant.js 2018-08-29 08:57:11 +02:00
TheCellMC 88e6c10fb2 Added support for hue motion sensor 2018-08-29 08:44:31 +02:00
TheCellMC 88524b7aed Added support for hue motion sensor 2018-08-29 08:44:22 +02:00
Koenkk b2a27dd64a Implement basic graphviz networkmap. #252 2018-08-28 22:07:57 +02:00
Koenkk 2a520b0e81 Raw implementation of network map. #252 2018-08-28 21:55:00 +02:00
Koenkk 0c32f25203 Update zigbee-shepherd-converters to 2.0.44 2018-08-25 00:11:42 +02:00
Koen Kanters 1aa020875a Merge pull request #218 from arontsang/master
Allow user to able use the same kind of click multiple times
2018-08-25 00:02:19 +02:00
Koen Kanters 9e5acdc94e Merge branch 'dev' into master 2018-08-24 23:59:39 +02:00
Koen Kanters 417879b6a8 Add force_update: true for action 2018-08-24 23:58:44 +02:00
Koen Kanters 4ee7845b2a Merge pull request #292 from carpenike/master
Added Self Signed CA Support
2018-08-17 18:41:36 +02:00
Koen Kanters fb9600d55d Change selfsigned to reject_unauthorized 2018-08-17 18:39:45 +02:00
Koen Kanters 47de3e20ae Remove selfsigned from configuration.yaml 2018-08-17 18:34:33 +02:00
Ryan Holt c00f091d7f removed trailing whitespace 2018-08-17 12:25:02 -04:00
Ryan Holt b0b2bd2444 adjusted whitespace to remove tabs and replace with spaces. 2018-08-17 12:22:27 -04:00
Ryan Holt 1e0c64caf5 made true default within commented section. 2018-08-17 12:17:18 -04:00
Ryan Holt db1fd6dd12 removed dockerfile 2018-08-17 12:16:47 -04:00
Ryan Holt 9ee0049248 adjusted to support self-signed certificates on mqtt 2018-08-17 12:15:44 -04:00
Aron Tsang 7403fc7ce4 Add force update 2018-07-27 03:17:09 +08:00
Aron Tsang 79d8cb69c0 Expire clicks after 1 second so you can click again 2018-07-27 03:00:07 +08:00
9 changed files with 680 additions and 1453 deletions
+30 -9
View File
@@ -3,13 +3,15 @@ const Zigbee = require('./zigbee');
const State = require('./state');
const logger = require('./util/logger');
const settings = require('./util/settings');
const ExtensionNetworkMap = require('./extension/networkMap');
const zigbeeShepherdConverters = require('zigbee-shepherd-converters');
const homeassistant = require('./homeassistant');
const objectAssignDeep = require(`object-assign-deep`);
const mqttConfigRegex = new RegExp(`${settings.get().mqtt.base_topic}/bridge/config/\\w+`, 'g');
const mqttDeviceRegex = new RegExp(`${settings.get().mqtt.base_topic}/[\\w\\s\\d]+/set`, 'g');
const mqttDevicePrefixRegex = new RegExp(`${settings.get().mqtt.base_topic}/[\\w\\s\\d]+/[\\w\\s\\d]+/set`, 'g');
const mqttDeviceRegex = new RegExp(`${settings.get().mqtt.base_topic}/[\\w\\s\\d.-]+/set`, 'g');
const mqttDevicePrefixRegex = new RegExp(`${settings.get().mqtt.base_topic}/[\\w\\s\\d.-]
+/[\\w\\s\\d.-]+/set`, 'g');
const pollInterval = 60 * 1000; // seconds * 1000.
const softResetTimeout = 3600 * 1000; // seconds * 1000.
@@ -94,6 +96,11 @@ class Controller {
});
}
// Initialize extensions.
this.extensions = [
new ExtensionNetworkMap(this.zigbee, this.mqtt, this.state),
];
// Resend all cached states.
this.sendAllCachedStates();
}
@@ -214,7 +221,15 @@ class Controller {
// Zigbee message receieved, reset soft reset timeout.
this.softResetTimeout(true);
logger.debug('Recieved zigbee message with data', JSON.stringify(message.data));
// Log the message.
let logMessage = `Recieved zigbee message of type '${message.type}' ` +
`with data '${JSON.stringify(message.data)}'`;
if (message.endpoints && message.endpoints[0].device) {
const device = message.endpoints[0].device;
logMessage += ` of device '${device.modelId}' (${device.ieeeAddr})`;
}
logger.debug(logMessage);
if (message.type == 'devInterview' && !settings.getDevice(message.data)) {
logger.info('Connecting with device...');
this.mqtt.log('pairing', 'connecting with device');
@@ -319,7 +334,7 @@ class Controller {
});
// Add device linkquality.
if (message.linkquality) {
if (message.hasOwnProperty('linkquality')) {
payload.linkquality = message.linkquality;
}
@@ -337,6 +352,12 @@ class Controller {
handleMQTTMessage(topic, message) {
logger.debug(`Recieved mqtt message on topic '${topic}' with data '${message}'`);
// Find extensions that could handle this.
const extensions = this.extensions.filter((e) => e.handleMQTTMessage);
// Call extensions.
const extensionResults = extensions.map((e) => e.handleMQTTMessage(topic, message));
if (topic.match(mqttConfigRegex)) {
this.handleMQTTMessageConfig(topic, message);
} else if (topic.match(mqttDeviceRegex) || topic.match(mqttDevicePrefixRegex)) {
@@ -348,13 +369,13 @@ class Controller {
clearTimeout(timer);
}, 20000);
}
} else {
} else if (!extensionResults.includes(true)) {
logger.warn(`Cannot handle MQTT message with topic '${topic}' and message '${message}'`);
}
}
handleMQTTMessageConfig(topic, message) {
const option = topic.split('/')[3];
const option = topic.split('/').slice(-1)[0];
if (option === 'permit_join') {
this.zigbee.permitJoin(message.toString().toLowerCase() === 'true');
@@ -458,8 +479,8 @@ class Controller {
}
handleMQTTMessageDevice(topic, message, withPrefix) {
const friendlyName = topic.split('/')[1];
const topicPrefix = withPrefix ? topic.split('/')[2] : '';
const friendlyName = topic.split('/').slice(-2)[0];
const topicPrefix = withPrefix ? topic.split('/').slice(-3)[0] : '';
// Map friendlyName to deviceID.
const deviceID = settings.getIDByFriendlyName(friendlyName);
@@ -520,7 +541,7 @@ class Controller {
}
};
this.zigbee.publish(deviceID, message.cid, message.cmd, message.zclData, ep, callback);
this.zigbee.publish(deviceID, message.cid, message.cmd, message.zclData, ep, message.type, callback);
published.push({message: message, converter: converter});
});
+51
View File
@@ -0,0 +1,51 @@
const settings = require('../util/settings');
class NetworkMap {
constructor(zigbee, mqtt, state) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
// Subscribe to topic.
this.topic = `${settings.get().mqtt.base_topic}/bridge/networkmap`;
this.mqtt.subscribe(this.topic);
// Set supported formats
this.supportedFormats = {
'raw': this.raw,
'graphviz': this.graphviz,
};
}
handleMQTTMessage(topic, message) {
message = message.toString();
if (topic === this.topic && this.supportedFormats.hasOwnProperty(message)) {
this.zigbee.networkScan((result)=> {
const converted = this.supportedFormats[message](result);
this.mqtt.publish(`bridge/networkmap/${message}`, converted, {});
});
return true;
}
}
raw(topology) {
return JSON.stringify(topology);
}
graphviz(topology) {
let text = 'digraph G {\n';
topology.forEach((item) => {
text += ` "${item.ieeeAddr}" [label="${item.ieeeAddr} (${item.status})"];\n`;
text += ` "${item.ieeeAddr}" -> "${item.parent}" [label="${item.lqi}"]\n`;
});
text += '}';
return text;
}
}
module.exports = NetworkMap;
+36
View File
@@ -46,6 +46,17 @@ const configurations = {
json_attributes: ['battery', 'voltage'],
},
},
'binary_sensor_gas': {
type: 'binary_sensor',
object_id: 'gas',
discovery_payload: {
payload_on: true,
payload_off: false,
value_template: '{{ value_json.gas }}',
device_class: 'gas',
json_attributes: [],
},
},
'binary_sensor_router': {
type: 'binary_sensor',
object_id: 'router',
@@ -106,6 +117,7 @@ const configurations = {
icon: 'mdi:toggle-switch',
value_template: '{{ value_json.click }}',
json_attributes: ['battery', 'voltage', 'action', 'duration'],
force_update: true,
},
},
'sensor_power': {
@@ -125,6 +137,7 @@ const configurations = {
icon: 'mdi:gesture-double-tap',
value_template: '{{ value_json.action }}',
json_attributes: ['battery', 'voltage', 'angle', 'side', 'from_side', 'to_side', 'brightness'],
force_update: true,
},
},
'sensor_brightness': {
@@ -137,6 +150,15 @@ const configurations = {
json_attributes: [],
},
},
'sensor_lock': {
type: 'sensor',
object_id: 'lock',
discovery_payload: {
icon: 'mdi:lock',
value_template: '{{ value_json.inserted }}',
json_attributes: ['forgotten', 'keyerror'],
},
},
// Light
'light_brightness_colortemp_xy': {
@@ -286,6 +308,10 @@ const mapping = {
'8718696598283': [configurations.light_brightness_colortemp],
'73693': [configurations.light_brightness_colortemp_xy],
'324131092621': [configurations.sensor_action],
'9290012607': [
configurations.binary_sensor_occupancy, configurations.sensor_temperature,
configurations.sensor_illuminance,
],
'GL-C-008': [configurations.light_brightness_colortemp_xy],
'STSS-MULT-001': [configurations.binary_sensor_contact],
'E11-G23': [configurations.light_brightness],
@@ -305,6 +331,16 @@ const mapping = {
'8718696548738': [configurations.light_brightness_colortemp],
'4052899926110': [configurations.light_brightness_colortemp_xy],
'Z01-CIA19NAE26': [configurations.light_brightness],
'E11-N1EA': [configurations.light_brightness_colortemp_xy],
'74283': [configurations.light_brightness],
'JTQJ-BF-01LM/BW': [configurations.binary_sensor_gas],
'50045': [configurations.light_brightness],
'AV2010/22': [configurations.binary_sensor_occupancy],
'3210-L': [configurations.switch],
'7299355PH': [configurations.light_brightness_colortemp_xy],
'A6121': [configurations.sensor_lock],
'433714': [configurations.light_brightness],
'3261030P7': [configurations.light_brightness_colortemp],
};
// A map of all discoverd devices
+10 -1
View File
@@ -30,6 +30,11 @@ class MQTT {
options.clientId = mqttSettings.client_id;
}
if (mqttSettings.hasOwnProperty('reject_unauthorized') && !mqttSettings.reject_unauthorized) {
logger.debug(`MQTT reject_unauthorized set false, ignoring certificate warnings.`);
options.rejectUnauthorized = false;
}
this.client = mqtt.connect(mqttSettings.server, options);
// Register callbacks.
@@ -65,7 +70,11 @@ class MQTT {
handleConnect() {
logger.info('Connected to MQTT server');
this.publish('bridge/state', 'online', {retain: true, qos: 0});
this.subscriptions.forEach((topic) => this.client.subscribe(topic));
this.subscriptions.forEach((topic) => this.subscribe(topic));
}
subscribe(topic) {
this.client.subscribe(topic);
}
handleMessage(topic, message) {
+19 -26
View File
@@ -1,6 +1,5 @@
const winston = require('winston');
const moment = require('moment');
const data = require('./data');
const settings = require('./settings');
const path = require('path');
const fs = require('fs');
@@ -8,21 +7,11 @@ const fx = require('mkdir-recursive');
const rimraf = require('rimraf');
// Determine the log level.
let level = winston.level.info;
if (process.env.DEBUG) {
level = 'debug';
} else if (settings.get().advanced && settings.get().advanced.log_level) {
level = settings.get().advanced.log_level;
}
const level = settings.get().advanced.log_level;
// Directoy to log to
let rootDirectory = path.join(data.getPath(), 'log');
if (settings.get().advanced && settings.get().advanced.log_directory) {
rootDirectory = settings.get().advanced.log_directory;
}
// Add start time to directory.
const directory = path.join(rootDirectory, moment(Date.now()).format('YYYY-MM-DD.HH:mm:ss'));
const timestamp = moment(Date.now()).format('YYYY-MM-DD.HH-mm-ss');
const directory = settings.get().advanced.log_directory.replace('%TIMESTAMP%', timestamp);
// Make sure that log directoy exsists
fx.mkdirSync(directory);
@@ -34,8 +23,8 @@ const logger = new (winston.Logger)({
filename: path.join(directory, 'log.txt'),
json: false,
level: level,
maxFiles: 3, // Max 3 files per run.
maxsize: 10000000, // 10MB // Only if Filename is static!
maxFiles: 3, // Keep last 3 files
maxsize: 10000000, // 10MB
timestamp: () => new Date().toLocaleString(),
}),
new (winston.transports.Console)({
@@ -54,16 +43,20 @@ logger.info(`Logging to directory: '${directory}'`);
logger.transports.console.level = level;
// Cleanup any old log directory.
let directories = fs.readdirSync(rootDirectory).map((d) => {
d = path.join(rootDirectory, d);
return {path: d, birth: fs.statSync(d).birthtimeMs};
});
if (settings.get().advanced.log_directory.includes('%TIMESTAMP%')) {
const rootDirectory = path.join(directory, '..');
directories.sort((a, b) => b.birth - a.birth);
directories = directories.slice(10, directories.length);
directories.forEach((dir) => {
logger.debug(`Removing old log directory '${dir.path}'`);
rimraf.sync(dir.path);
});
let directories = fs.readdirSync(rootDirectory).map((d) => {
d = path.join(rootDirectory, d);
return {path: d, birth: fs.statSync(d).birthtimeMs};
});
directories.sort((a, b) => b.birth - a.birth);
directories = directories.slice(10, directories.length);
directories.forEach((dir) => {
logger.debug(`Removing old log directory '${dir.path}'`);
rimraf.sync(dir.path);
});
}
module.exports = logger;
+10 -1
View File
@@ -2,6 +2,15 @@ const yaml = require('js-yaml');
const fs = require('fs');
const data = require('./data');
const file = data.joinPath('configuration.yaml');
const objectAssignDeep = require(`object-assign-deep`);
const path = require('path');
const defaults = {
advanced: {
log_directory: path.join(data.getPath(), 'log', '%TIMESTAMP%'),
log_level: process.env.DEBUG ? 'debug' : 'info',
},
};
let settings = read();
@@ -57,7 +66,7 @@ function changeFriendlyName(old, new_) {
}
module.exports = {
get: () => settings,
get: () => objectAssignDeep.noMutate(defaults, settings),
write: () => write(),
getDevice: (id) => settings.devices ? settings.devices[id] : null,
addDevice: (id) => addDevice(id),
+20 -3
View File
@@ -183,7 +183,7 @@ class Zigbee {
return this.shepherd.find(device.ieeeAddr, 1);
}
publish(deviceID, cid, cmd, zclData, ep, callback) {
publish(deviceID, cid, cmd, zclData, ep, type, callback) {
const device = this._findDevice(deviceID, ep);
if (!device) {
logger.error(`Zigbee cannot publish message to device because '${deviceID}' not known by zigbee-shepherd`);
@@ -191,7 +191,8 @@ class Zigbee {
}
logger.info(`Zigbee publish to '${deviceID}', ${cid} - ${cmd} - ${JSON.stringify(zclData)} - ${ep}`);
device.functional(cid, cmd, zclData, (error) => {
const callback_ = (error) => {
if (error) {
logger.error(
`Zigbee publish to '${deviceID}', ${cid} - ${cmd} - ${JSON.stringify(zclData)} - ${ep} ` +
@@ -199,7 +200,15 @@ class Zigbee {
}
callback(error);
});
};
if (type === 'functional') {
device.functional(cid, cmd, zclData, callback_);
} else if (type === 'foundation') {
device.foundation(cid, cmd, [zclData], callback_);
} else {
logger.error(`Unknown zigbee publish type ${type}`);
}
}
read(deviceID, cid, attr, ep, callback) {
@@ -212,6 +221,14 @@ class Zigbee {
device.read(cid, attr, callback);
}
networkScan(callback) {
logger.info('Starting network scan...');
this.shepherd.lqiScan().then((result) => {
logger.info('Network scan completed');
callback(result);
});
}
registerOnAfIncomingMsg(ieeeAddr, ep) {
const device = this._findDevice(ieeeAddr, ep);
device.onAfIncomingMsg = (message) => {
+501 -1410
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "zigbee2mqtt",
"version": "0.1.3",
"version": "0.1.5",
"description": "Zigbee to MQTT bridge using zigbee-shepherd",
"main": "index.js",
"repository": {
@@ -40,8 +40,8 @@
"object-assign-deep": "*",
"rimraf": "*",
"winston": "2.4.2",
"zcl-packet": "git+https://github.com/Koenkk/zcl-packet.git#b7d5b4478a88cd3fc65328c6dc94572c277c7d3e",
"zigbee-shepherd": "git+https://github.com/Koenkk/zigbee-shepherd.git#7673fc5a285dc93d2e466bc2aa7134220e1fb134",
"zcl-packet": "git+https://github.com/Koenkk/zcl-packet.git#8f17e5540946f9be198d737a879e334c24dbf20d",
"zigbee-shepherd": "git+https://github.com/Koenkk/zigbee-shepherd.git#c096ed6719a6c941217c560b4cdcc04e4dd34c3b",
"zigbee-shepherd-converters": "*"
},
"devDependencies": {