mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-08-29 07:08:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8c8417192 | ||
|
|
56a0f6256b | ||
|
|
197a3cdebc | ||
|
|
c520985a4f | ||
|
|
931926cd96 | ||
|
|
427c99cd83 | ||
|
|
c2cd02e790 | ||
|
|
a921394240 | ||
|
|
21f047f4aa | ||
|
|
9a70c95672 | ||
|
|
fc2e93d96f | ||
|
|
494c15a731 | ||
|
|
23a2feb7cf | ||
|
|
f4ceccaa9b | ||
|
|
b4398e21c3 | ||
|
|
3900d56d6e | ||
|
|
08f64b96be | ||
|
|
8411c0b30d | ||
|
|
43260a3a83 | ||
|
|
6f4013fd94 | ||
|
|
426a89914f | ||
|
|
4fa1a4c57a | ||
|
|
5ddfcea8f3 | ||
|
|
502c0cb852 | ||
|
|
07d8fd5605 | ||
|
|
445ccb5bbd | ||
|
|
74c8758a3b | ||
|
|
1f6f73e8d2 | ||
|
|
04b2f24d6b | ||
|
|
5e96c46a7a | ||
|
|
ec4f5e1472 | ||
|
|
32a512ea6b | ||
|
|
46a3461e76 | ||
|
|
fe92e9c421 | ||
|
|
2f02168fcb | ||
|
|
2ba86a13eb | ||
|
|
7dd1c75be0 | ||
|
|
b5f0e9b958 | ||
|
|
bd901ec9dd |
+7
-5
@@ -4,14 +4,16 @@
|
||||
},
|
||||
"extends": ["eslint:recommended", "google"],
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
},
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"require-jsdoc": "off",
|
||||
"indent": ["error", 4],
|
||||
"max-len": ["error", { "code": 120 }]
|
||||
}
|
||||
"max-len": ["error", { "code": 120 }],
|
||||
"mocha/no-exclusive-tests": "error"
|
||||
},
|
||||
"plugins": [
|
||||
"mocha"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Unsupported device
|
||||
First check: https://github.com/Koenkk/zigbee2mqtt/wiki/How-to-support-new-devices
|
||||
|
||||
|
||||
Bug report
|
||||
- First make sure your on the latest version of zigbee2mqtt.
|
||||
- Make sure you are running the latest CC253X firmware from https://github.com/koenkk/z-stack-firmware.
|
||||
- Provide a clear description of the problem.
|
||||
- If applicable, provide steps how to reproduce the problem.
|
||||
- Provide a log with `log_level` set to `debug`, see https://github.com/Koenkk/zigbee2mqtt/wiki/Configuration
|
||||
- DON'T copy logs directly here, post a link to https://hastebin.com/ or https://pastebin.com/.
|
||||
+3
-1
@@ -60,4 +60,6 @@ typings/
|
||||
# data
|
||||
data/database.db
|
||||
data/config.json
|
||||
data/log*.txt
|
||||
data/log*.txt
|
||||
data/state.json
|
||||
data/log
|
||||
+3
-2
@@ -11,11 +11,12 @@ node_js:
|
||||
install:
|
||||
- npm install
|
||||
|
||||
script:
|
||||
before_script:
|
||||
- npm test
|
||||
- npm run verify-homeassistant-mapping
|
||||
- npm run eslint
|
||||
|
||||
after_success:
|
||||
script:
|
||||
- ".travis/docker.sh"
|
||||
- ".travis/wiki.sh"
|
||||
- ".travis/trigger-downstream.sh"
|
||||
|
||||
@@ -20,11 +20,11 @@ function travis_trigger() {
|
||||
"https://api.travis-ci.org/repo/${org}%2F${repo}/requests"
|
||||
}
|
||||
|
||||
# Only trigger downstream if on master branch and not pull request
|
||||
if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]
|
||||
# Only trigger downstream if on dev branch and not pull request
|
||||
if [ "$TRAVIS_BRANCH" = "dev" -a "$TRAVIS_PULL_REQUEST" = "false" ]
|
||||
then
|
||||
echo "Triggering build of downstream projects!"
|
||||
travis_trigger "danielwelch" "hassio-zigbee2mqtt" "master"
|
||||
else
|
||||
echo "Not triggering build of downstream projects, triggered by pull request or not on master branch"
|
||||
echo "Not triggering build of downstream projects, triggered by pull request or not on dev branch"
|
||||
fi
|
||||
|
||||
+22
-8
@@ -1,5 +1,6 @@
|
||||
const MQTT = require('./mqtt');
|
||||
const Zigbee = require('./zigbee');
|
||||
const State = require('./state');
|
||||
const logger = require('./util/logger');
|
||||
const settings = require('./util/settings');
|
||||
const zigbeeShepherdConverters = require('zigbee-shepherd-converters');
|
||||
@@ -32,7 +33,7 @@ class Controller {
|
||||
constructor() {
|
||||
this.zigbee = new Zigbee();
|
||||
this.mqtt = new MQTT();
|
||||
this.stateCache = {};
|
||||
this.state = new State();
|
||||
this.configured = [];
|
||||
this.handleZigbeeMessage = this.handleZigbeeMessage.bind(this);
|
||||
this.handleMQTTMessage = this.handleMQTTMessage.bind(this);
|
||||
@@ -99,8 +100,8 @@ class Controller {
|
||||
|
||||
sendAllCachedStates() {
|
||||
this.zigbee.getAllClients().forEach((device) => {
|
||||
if (this.stateCache.hasOwnProperty(device.ieeeAddr)) {
|
||||
this.mqttPublishDeviceState(device.ieeeAddr, this.stateCache[device.ieeeAddr], false);
|
||||
if (this.state.exists(device.ieeeAddr)) {
|
||||
this.mqttPublishDeviceState(device.ieeeAddr, this.state.get(device.ieeeAddr), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -152,6 +153,7 @@ class Controller {
|
||||
}
|
||||
|
||||
stop(callback) {
|
||||
this.state.save();
|
||||
this.mqtt.disconnect();
|
||||
this.pollTimer(false);
|
||||
this.softResetTimeout(false);
|
||||
@@ -159,7 +161,11 @@ class Controller {
|
||||
}
|
||||
|
||||
configureDevice(device) {
|
||||
let friendlyName = 'unknown';
|
||||
const ieeeAddr = device.ieeeAddr;
|
||||
if (settings.getDevice(ieeeAddr)) {
|
||||
friendlyName = settings.getDevice(ieeeAddr).friendly_name;
|
||||
}
|
||||
if (ieeeAddr && device.modelId && !this.configured.includes(ieeeAddr)) {
|
||||
const mappedModel = zigbeeShepherdConverters.findByZigbeeModel(device.modelId);
|
||||
|
||||
@@ -167,9 +173,9 @@ class Controller {
|
||||
if (mappedModel && mappedModel.configure) {
|
||||
mappedModel.configure(ieeeAddr, this.zigbee.shepherd, this.zigbee.getCoordinator(), (ok, msg) => {
|
||||
if (ok) {
|
||||
logger.info(`Succesfully configured ${ieeeAddr}`);
|
||||
logger.info(`Succesfully configured ${friendlyName} ${ieeeAddr}`);
|
||||
} else {
|
||||
logger.error(`Failed to configure ${ieeeAddr}`);
|
||||
logger.error(`Failed to configure ${friendlyName} ${ieeeAddr}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -312,6 +318,11 @@ class Controller {
|
||||
}
|
||||
});
|
||||
|
||||
// Add device linkquality.
|
||||
if (message.linkquality) {
|
||||
payload.linkquality = message.linkquality;
|
||||
}
|
||||
|
||||
this.mqttPublishDeviceState(device.ieeeAddr, payload, cache);
|
||||
};
|
||||
|
||||
@@ -388,6 +399,9 @@ class Controller {
|
||||
// Remove from configuration.yaml
|
||||
settings.removeDevice(deviceID);
|
||||
|
||||
// Remove from state
|
||||
this.state.remove(deviceID);
|
||||
|
||||
logger.info(`Successfully removed ${deviceID}`);
|
||||
this.mqtt.log('device_removed', message);
|
||||
};
|
||||
@@ -544,13 +558,13 @@ class Controller {
|
||||
mqttPublishDeviceState(deviceID, payload, cache) {
|
||||
if (cacheState) {
|
||||
// Add cached state to payload
|
||||
if (this.stateCache[deviceID]) {
|
||||
payload = objectAssignDeep.noMutate(this.stateCache[deviceID], payload);
|
||||
if (this.state.exists(deviceID)) {
|
||||
payload = objectAssignDeep.noMutate(this.state.get(deviceID), payload);
|
||||
}
|
||||
|
||||
// Update state cache with new state.
|
||||
if (cache) {
|
||||
this.stateCache[deviceID] = payload;
|
||||
this.state.set(deviceID, payload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-18
@@ -191,28 +191,21 @@ const configurations = {
|
||||
command_topic: true,
|
||||
},
|
||||
},
|
||||
'switch_left': {
|
||||
};
|
||||
|
||||
const switchWithPostfix = (postfix) => {
|
||||
return {
|
||||
type: 'switch',
|
||||
object_id: 'switch_left',
|
||||
object_id: `switch_${postfix}`,
|
||||
discovery_payload: {
|
||||
payload_off: 'OFF',
|
||||
payload_on: 'ON',
|
||||
value_template: '{{ value_json.state_left }}',
|
||||
value_template: `{{ value_json.state_${postfix} }}`,
|
||||
command_topic: true,
|
||||
command_topic_prefix: 'left',
|
||||
command_topic_prefix: postfix,
|
||||
json_attributes: [`button_${postfix}`],
|
||||
},
|
||||
},
|
||||
'switch_right': {
|
||||
type: 'switch',
|
||||
object_id: 'switch_right',
|
||||
discovery_payload: {
|
||||
payload_off: 'OFF',
|
||||
payload_on: 'ON',
|
||||
value_template: '{{ value_json.state_right }}',
|
||||
command_topic: true,
|
||||
command_topic_prefix: 'right',
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// Map homeassitant configurations to devices.
|
||||
@@ -223,7 +216,7 @@ const mapping = {
|
||||
'WXKG03LM': [configurations.sensor_click],
|
||||
'WXKG02LM': [configurations.sensor_click],
|
||||
'QBKG04LM': [configurations.switch],
|
||||
'QBKG03LM': [configurations.switch_left, configurations.switch_right],
|
||||
'QBKG03LM': [switchWithPostfix('left'), switchWithPostfix('right')],
|
||||
'WSDCGQ01LM': [configurations.sensor_temperature, configurations.sensor_humidity],
|
||||
'WSDCGQ11LM': [configurations.sensor_temperature, configurations.sensor_humidity, configurations.sensor_pressure],
|
||||
'RTCGQ01LM': [configurations.binary_sensor_occupancy],
|
||||
@@ -281,7 +274,7 @@ const mapping = {
|
||||
'SL 110 W': [configurations.light_brightness],
|
||||
'AA68199': [configurations.light_brightness_colortemp],
|
||||
'QBKG11LM': [configurations.switch, configurations.sensor_power],
|
||||
'QBKG12LM': [configurations.switch_left, configurations.switch_right, configurations.sensor_power],
|
||||
'QBKG12LM': [switchWithPostfix('left'), switchWithPostfix('right'), configurations.sensor_power],
|
||||
'K2RGBW01': [configurations.light_brightness_colortemp_xy],
|
||||
'9290011370': [configurations.light_brightness],
|
||||
'DNCKATSW001': [configurations.switch],
|
||||
@@ -298,6 +291,20 @@ const mapping = {
|
||||
'E11-G23': [configurations.light_brightness],
|
||||
'AC03845': [configurations.light_brightness_colortemp_xy],
|
||||
'AC03641': [configurations.light_brightness],
|
||||
'FB56+ZSW05HG1.2': [configurations.switch],
|
||||
'72922-A': [configurations.switch],
|
||||
'AC03642': [configurations.light_brightness_colortemp],
|
||||
'DNCKATSW002': [switchWithPostfix('left'), switchWithPostfix('right')],
|
||||
'DNCKATSW003': [switchWithPostfix('left'), switchWithPostfix('right'), switchWithPostfix('center')],
|
||||
'DNCKATSW004': [
|
||||
switchWithPostfix('bottom_left'), switchWithPostfix('bottom_right'),
|
||||
switchWithPostfix('top_left'), switchWithPostfix('top_right'),
|
||||
],
|
||||
'BY 165': [configurations.light_brightness],
|
||||
'ZLED-2709': [configurations.light_brightness],
|
||||
'8718696548738': [configurations.light_brightness_colortemp],
|
||||
'4052899926110': [configurations.light_brightness_colortemp_xy],
|
||||
'Z01-CIA19NAE26': [configurations.light_brightness],
|
||||
};
|
||||
|
||||
// A map of all discoverd devices
|
||||
|
||||
+14
-3
@@ -12,7 +12,14 @@ class MQTT {
|
||||
const mqttSettings = settings.get().mqtt;
|
||||
logger.info(`Connecting to MQTT server at ${mqttSettings.server}`);
|
||||
|
||||
const options = {};
|
||||
const options = {
|
||||
will: {
|
||||
topic: this.prefixTopic('bridge/state'),
|
||||
payload: 'offline',
|
||||
retain: true,
|
||||
},
|
||||
};
|
||||
|
||||
if (mqttSettings.user && mqttSettings.password) {
|
||||
options.username = mqttSettings.user;
|
||||
options.password = mqttSettings.password;
|
||||
@@ -68,8 +75,7 @@ class MQTT {
|
||||
}
|
||||
|
||||
publish(topic, payload, options, callback, baseTopic) {
|
||||
baseTopic = baseTopic ? baseTopic : settings.get().mqtt.base_topic;
|
||||
topic = `${baseTopic}/${topic}`;
|
||||
topic = this.prefixTopic(topic, baseTopic);
|
||||
|
||||
if (!this.client || this.client.reconnecting) {
|
||||
logger.error(`Not connected to MQTT server!`);
|
||||
@@ -81,6 +87,11 @@ class MQTT {
|
||||
this.client.publish(topic, payload, options, callback);
|
||||
}
|
||||
|
||||
prefixTopic(topic, baseTopic) {
|
||||
baseTopic = baseTopic ? baseTopic : settings.get().mqtt.base_topic;
|
||||
return `${baseTopic}/${topic}`;
|
||||
}
|
||||
|
||||
log(type, message) {
|
||||
const payload = {type: type, message: message};
|
||||
this.publish('bridge/log', JSON.stringify(payload), {retain: false});
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
const logger = require('./util/logger');
|
||||
const data = require('./util/data');
|
||||
const fs = require('fs');
|
||||
|
||||
const saveInterval = 1000 * 60 * 5; // 5 minutes
|
||||
|
||||
class State {
|
||||
constructor() {
|
||||
this.state = {};
|
||||
this.file = data.joinPath('state.json');
|
||||
this._load();
|
||||
|
||||
// Save the state on every interval
|
||||
this.timer = setInterval(() => this.save(), saveInterval);
|
||||
}
|
||||
|
||||
_load() {
|
||||
if (fs.existsSync(this.file)) {
|
||||
try {
|
||||
this.state = JSON.parse(fs.readFileSync(this.file, 'utf8'));
|
||||
logger.debug(`Loaded state from file ${this.file}`);
|
||||
} catch (e) {
|
||||
logger.debug(`Failed to load state from file ${this.file} (corrupt file?)`);
|
||||
}
|
||||
} else {
|
||||
logger.debug(`Can't load state from file ${this.file} (doesn't exsist)`);
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
logger.debug(`Saving state to file ${this.file}`);
|
||||
const json = JSON.stringify(this.state, null, 4);
|
||||
fs.writeFileSync(this.file, json, 'utf8');
|
||||
}
|
||||
|
||||
exists(ID) {
|
||||
return this.state.hasOwnProperty(ID);
|
||||
}
|
||||
|
||||
get(ID) {
|
||||
return this.state[ID];
|
||||
}
|
||||
|
||||
set(ID, state) {
|
||||
this.state[ID] = state;
|
||||
}
|
||||
|
||||
remove(ID) {
|
||||
if (this.exists(ID)) {
|
||||
delete this.state[ID];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = State;
|
||||
@@ -11,4 +11,5 @@ if (process.env.ZIGBEE2MQTT_DATA) {
|
||||
|
||||
module.exports = {
|
||||
joinPath: (file) => path.join(dataPath, file),
|
||||
getPath: () => dataPath,
|
||||
};
|
||||
|
||||
+46
-14
@@ -1,37 +1,69 @@
|
||||
const winston = require('winston');
|
||||
const moment = require('moment');
|
||||
const data = require('./data');
|
||||
const settings = require('./settings');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const fx = require('mkdir-recursive');
|
||||
const rimraf = require('rimraf');
|
||||
|
||||
let logLevel = '';
|
||||
// Determine the log level.
|
||||
let level = winston.level.info;
|
||||
if (process.env.DEBUG) {
|
||||
logLevel = 'debug';
|
||||
level = 'debug';
|
||||
} else if (settings.get().advanced && settings.get().advanced.log_level) {
|
||||
logLevel = settings.get().advanced.log_level;
|
||||
} else {
|
||||
logLevel = winston.level.info;
|
||||
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'));
|
||||
|
||||
// Make sure that log directoy exsists
|
||||
fx.mkdirSync(directory);
|
||||
|
||||
// Create logger
|
||||
const logger = new (winston.Logger)({
|
||||
transports: [
|
||||
new (winston.transports.File)({
|
||||
filename: data.joinPath('log.txt'),
|
||||
filename: path.join(directory, 'log.txt'),
|
||||
json: false,
|
||||
level: logLevel,
|
||||
maxFiles: 3,
|
||||
maxsize: 10000000, // 10MB
|
||||
level: level,
|
||||
maxFiles: 3, // Max 3 files per run.
|
||||
maxsize: 10000000, // 10MB // Only if Filename is static!
|
||||
timestamp: () => new Date().toLocaleString(),
|
||||
}),
|
||||
new (winston.transports.Console)({
|
||||
timestamp: () => new Date().toLocaleString(),
|
||||
formatter: function(options) {
|
||||
return options.timestamp() + ' ' +
|
||||
winston.config.colorize(options.level, options.level.toUpperCase()) + ' ' +
|
||||
(options.message ? options.message : '') +
|
||||
(options.meta && Object.keys(options.meta).length ? '\n\t'+ JSON.stringify(options.meta) : '' );
|
||||
return winston.config.colorize(options.level, ' zigbee2mqtt:' + options.level.toLowerCase()) + ' ' +
|
||||
options.timestamp() + ' ' + (options.message ? options.message : '') +
|
||||
(options.meta && Object.keys(options.meta).length ? '\n\t'+ JSON.stringify(options.meta) : '' );
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
logger.transports.console.level = logLevel;
|
||||
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};
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
+17
-3
@@ -13,7 +13,7 @@ const shepherdSettings = {
|
||||
},
|
||||
dbPath: data.joinPath('database.db'),
|
||||
sp: {
|
||||
baudrate: advancedSettings && advancedSettings.baudrate ? advancedSettings.baudrate : 115200,
|
||||
baudRate: advancedSettings && advancedSettings.baudrate ? advancedSettings.baudrate : 115200,
|
||||
rtscts: advancedSettings && (typeof(advancedSettings.rtscts) === 'boolean') ? advancedSettings.rtscts : true,
|
||||
},
|
||||
};
|
||||
@@ -68,6 +68,7 @@ class Zigbee {
|
||||
|
||||
_logStartupInfo() {
|
||||
logger.info('zigbee-shepherd started');
|
||||
logger.info(`Coordinator firmware version: '${this.shepherd.info().firmware.revision}'`);
|
||||
logger.debug(`zigbee-shepherd info: ${JSON.stringify(this.shepherd.info())}`);
|
||||
}
|
||||
|
||||
@@ -153,11 +154,16 @@ class Zigbee {
|
||||
}
|
||||
|
||||
ping(deviceID) {
|
||||
let friendlyName = 'unknown';
|
||||
const device = this.shepherd._findDevByAddr(deviceID);
|
||||
const ieeeAddr = device.ieeeAddr;
|
||||
if (settings.getDevice(ieeeAddr)) {
|
||||
friendlyName = settings.getDevice(ieeeAddr).friendly_name;
|
||||
}
|
||||
|
||||
if (device) {
|
||||
// Note: checkOnline has the callback argument but does not call callback
|
||||
logger.debug(`Check online ${deviceID}`);
|
||||
logger.debug(`Check online ${friendlyName} ${deviceID}`);
|
||||
this.shepherd.controller.checkOnline(device);
|
||||
}
|
||||
}
|
||||
@@ -185,7 +191,15 @@ class Zigbee {
|
||||
}
|
||||
|
||||
logger.info(`Zigbee publish to '${deviceID}', ${cid} - ${cmd} - ${JSON.stringify(zclData)} - ${ep}`);
|
||||
device.functional(cid, cmd, zclData, callback);
|
||||
device.functional(cid, cmd, zclData, (error) => {
|
||||
if (error) {
|
||||
logger.error(
|
||||
`Zigbee publish to '${deviceID}', ${cid} - ${cmd} - ${JSON.stringify(zclData)} - ${ep} ` +
|
||||
`failed with error ${error}`);
|
||||
}
|
||||
|
||||
callback(error);
|
||||
});
|
||||
}
|
||||
|
||||
read(deviceID, cid, attr, ep, callback) {
|
||||
|
||||
Generated
+4377
-1504
File diff suppressed because it is too large
Load Diff
+24
-13
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zigbee2mqtt",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"description": "Zigbee to MQTT bridge using zigbee-shepherd",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
@@ -17,10 +17,12 @@
|
||||
"cc2531"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"coverage": "nyc --all report --reporter=text mocha --recursive --timeout=3000",
|
||||
"docgen": "node support/docgen.js",
|
||||
"verify-homeassistant-mapping": "node support/verify-homeassistant-mapping.js",
|
||||
"eslint": "node_modules/.bin/eslint ."
|
||||
"eslint": "node_modules/.bin/eslint .",
|
||||
"start": "node index.js",
|
||||
"test": "mocha --recursive",
|
||||
"verify-homeassistant-mapping": "node support/verify-homeassistant-mapping.js"
|
||||
},
|
||||
"author": "Koen Kanters",
|
||||
"license": "GPL-3.0",
|
||||
@@ -29,18 +31,27 @@
|
||||
},
|
||||
"homepage": "https://github.com/Koenkk/zigbee2mqtt/wiki",
|
||||
"dependencies": {
|
||||
"object-assign-deep": "*",
|
||||
"mqtt": "*",
|
||||
"winston": "2.4.2",
|
||||
"zigbee-shepherd": "git+https://github.com/Koenkk/zigbee-shepherd.git#2078557a485466c032cc26b2cd2b8ac29edeceac",
|
||||
"zigbee-shepherd-converters": "2.0.34",
|
||||
"json2yaml": "*",
|
||||
"zcl-packet": "git+https://github.com/Koenkk/zcl-packet.git#3ea8912f9d228b59fad554064d15ed9be7897a7f",
|
||||
"git-last-commit": "*",
|
||||
"js-yaml": "*",
|
||||
"git-last-commit": "*"
|
||||
"json2yaml": "*",
|
||||
"mkdir-recursive": "*",
|
||||
"moment": "*",
|
||||
"mqtt": "*",
|
||||
"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",
|
||||
"zigbee-shepherd-converters": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "*",
|
||||
"chai-spies": "*",
|
||||
"eslint": "*",
|
||||
"eslint-config-google": "*"
|
||||
"eslint-config-google": "*",
|
||||
"eslint-plugin-mocha": "*",
|
||||
"mocha": "*",
|
||||
"nyc": "*",
|
||||
"proxyquire": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* global describe, it */
|
||||
|
||||
const chai = require('chai');
|
||||
const proxyquire = require('proxyquire').noPreserveCache();
|
||||
const data = () => proxyquire('../lib/util/data.js', {});
|
||||
const path = require('path');
|
||||
|
||||
describe('Data', () => {
|
||||
describe('Get path', () => {
|
||||
it('Should return correct path', () => {
|
||||
const expected = path.normalize(path.join(__dirname, '..', 'data'));
|
||||
const actual = data().getPath();
|
||||
chai.assert.strictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('Should return correct path when ZIGBEE2MQTT_DATA set', () => {
|
||||
const expected = path.join('var', 'zigbee2mqtt');
|
||||
process.env.ZIGBEE2MQTT_DATA = expected;
|
||||
const actual = data().getPath();
|
||||
chai.assert.strictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user