Showing preview only (3,395K chars total). Download the full file or copy to clipboard to get everything.
Repository: Z-Wave-Me/home-automation
Branch: master
Commit: ccbf5c355175
Files: 454
Total size: 3.1 MB
Directory structure:
gitextract_gic6ajyx/
├── .jscsrc
├── .jshintrc
├── .syscommands
├── CHANGELOG.md
├── README.md
├── StorageProvider.js
├── Utils.js
├── Webserver.js
├── WebserverRequestRouter.js
├── ZAutomationAPIProvider.js
├── apiary.apib
├── classes/
│ ├── AuthController.js
│ ├── AutomationController.js
│ ├── AutomationModule.js
│ ├── DevicesCollection.js
│ └── VirtualDevice.js
├── defaultConfigs/
│ ├── README
│ ├── config.json
│ ├── config.json_WB
│ ├── config.json_ttyACM0
│ ├── config.json_ttyACM0_ZBW-WD
│ ├── config.json_ttyACM0_ZBW-no
│ ├── config.json_ttyAMA0
│ ├── config.json_ttyAMA0_NonExpert
│ ├── config.json_ttyS0
│ ├── config.json_ttyS0-JBox
│ ├── config.json_ttyS0-ReHub
│ ├── config.json_ttyS1
│ ├── config.json_ttyUSB0_ZBW-no_vDev-no
│ └── config.json_windows
├── lang/
│ ├── cn.json
│ ├── cz.json
│ ├── de.json
│ ├── en.json
│ ├── es.json
│ ├── fi.json
│ ├── fr.json
│ ├── it.json
│ ├── pt.json
│ ├── ru.json
│ ├── se.json
│ ├── sk.json
│ └── sv.json
├── lib/
│ ├── BAOS_API_2011_01_29_001.js
│ ├── IntelHex2bin.js
│ ├── LimitedArray.js
│ ├── base64.js
│ ├── eventemitter2.js
│ ├── underscore-umd-min.js
│ └── underscore.js
├── main.js
├── modules/
│ ├── Alexa/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── AutoLock/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── AutoOff/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── BatteryPolling/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── BindDevices/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── Camera/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── CloudBackup/
│ │ ├── Readme.md
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── CodeDevice/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── CorrectValue/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── CounterTriggeringSensor/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── Cron/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── CustomUserCode/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── CustomUserCodeLoader/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── CustomUserCodeZWay/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── DecomposeRGB/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── DelayedScene/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── DeviceHistory/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── DummyDevice/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── EasyScripting/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ ├── compile.sh
│ │ │ ├── postRender-with-comments.js
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── EdimaxSP1101/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── EdimaxSP2101/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── EnOcean/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── FosCam9805/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── FosCam9821/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── FosCam9826/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── FosCam9828/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── GlobalCache/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── GoogleHome/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── GroupDevices/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── HTTPDevice/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── HazardNotification/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── Heating/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── HomeKitGate/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── IfThen/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── ImportRemoteHA/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── InbandNotifications/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── InfoWidget/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── LightMotionRockerAutocontrol/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ └── en.json
│ │ └── module.json
│ ├── LightScene/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── LogicalRules/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── MQTTClient/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ └── en.json
│ │ └── module.json
│ ├── MatterGate/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── MobileAppSupport/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── MultilineSensor/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── NotificationChannelEmail/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ └── en.json
│ │ └── module.json
│ ├── NotificationFiltering/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ └── en.json
│ │ └── module.json
│ ├── NotificationSend/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ └── en.json
│ │ └── module.json
│ ├── OpenRemoteHelpers/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── OpenWeather/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── PhilioHW/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── PoppCam/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── RGB/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── RemoteAccess/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── RoundRobinScenes/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── Rules/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── Scenes/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── ScheduledScene/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── Schedules/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── Security/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── SecurityMode/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── SensorValueLogging/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── SensorsPolling/
│ │ ├── htdocs/
│ │ │ └── js/
│ │ │ └── postRender.js
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── SensorsPollingLogging/
│ │ ├── index.js
│ │ └── module.json
│ ├── SmartLight/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── Sonos/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── SwitchControlGenerator/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── SwitchPolling/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── TPLinkHS100/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── TPLinkHS110/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── TagOnOff/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── TamperAutoOff/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── TechnaxxTX65/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── TechnaxxTX66/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ └── module.json
│ ├── TechnaxxTX67/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ └── en.json
│ │ ├── module.json
│ │ └── patchnotes.txt
│ ├── ThermostatDevice/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── VistaCam/
│ │ ├── TVPIP320PIV1/
│ │ │ ├── index.js
│ │ │ ├── lang/
│ │ │ │ ├── de.json
│ │ │ │ └── en.json
│ │ │ └── module.json
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── ZMEOpenWRT/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── ZMatter/
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ └── module.json
│ ├── ZWave/
│ │ ├── cmd_classes.json
│ │ ├── index.js
│ │ ├── lang/
│ │ │ ├── de.json
│ │ │ ├── en.json
│ │ │ └── ru.json
│ │ ├── module.json
│ │ └── postfix.json
│ └── Zigbee/
│ ├── index.js
│ ├── lang/
│ │ ├── de.json
│ │ ├── en.json
│ │ └── ru.json
│ └── module.json
├── modulesCategories.json
├── release.sh
├── router.js
└── updateBackendConfig.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .jscsrc
================================================
{
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch", "case"],
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
"requireSpaceBeforeBlockStatements": true,
"requireParenthesesAroundIIFE": true,
"requireSpacesInConditionalExpression": {
"afterTest": true,
"beforeConsequent": true,
"afterConsequent": true,
"beforeAlternate": true
},
"requireSpacesInFunctionExpression": {
"beforeOpeningRoundBrace": true,
"beforeOpeningCurlyBrace": true
},
"requireSpacesInFunctionDeclaration": {
"beforeOpeningCurlyBrace": true
},
"disallowSpacesInFunctionDeclaration": {
"beforeOpeningRoundBrace": true
},
"requireMultipleVarDecl": true,
"requireBlocksOnNewline": true,
"disallowPaddingNewlinesInBlocks": true,
"disallowEmptyBlocks": true,
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
"requireSpaceBeforeBinaryOperators": ["=", "+", "-", "/", "*", "==", "===", "!=", "!=="],
"requireSpaceAfterBinaryOperators": ["=", ",", "+", "-", "/", "*", "==", "===", "!=", "!=="],
"disallowImplicitTypeConversion": ["numeric", "boolean", "binary", "string"],
"disallowKeywords": ["with", "eval"],
"disallowMultipleLineStrings": true,
"disallowMultipleLineBreaks": true,
"disallowMixedSpacesAndTabs": true,
"disallowTrailingWhitespace": true,
"disallowTrailingComma": true,
"disallowKeywordsOnNewLine": ["else"],
"requireCapitalizedConstructors": true,
"safeContextKeyword": "self",
"disallowYodaConditions": true,
"validateJSDoc": {
"checkParamNames": true,
"requireParamTypes": true,
"checkRedundantParams": true
},
"excludeFiles": [
"node_modules/**",
"lib/**",
"storage/**",
"system/*.json"
],
"fileExtensions": [".js"]
}
================================================
FILE: .jshintrc
================================================
{
"nonew": true,
"curly": true,
"noarg": true,
"forin": true,
"noempty": true,
"eqeqeq":true,
"strict":true,
"undef":true,
"bitwise":true,
"browser":true,
"devel":true,
"mocha": true,
"node": true,
"globals": {
"describe": true,
"it": true,
"executeFile": true,
"_": true,
"Core": true,
"global": true
}
}
================================================
FILE: .syscommands
================================================
cat /etc/z-way/box_type
reboot
cat /etc/timezone
sh automation/lib/configAP.sh
sh automation/lib/fetchLog.sh
sh automation/lib/timezone.sh
tail -1000 /var/log/z-way-server.log | tac
ip a s dev eth0 | sed -n 's/.*inet \([0-9.]*\)\/.*/\1/p' | head -n 1
cat /sys/class/net/eth0/address
================================================
FILE: CHANGELOG.md
================================================
## 10.10.2024 v5.0.1
New features:
* Added externalUrl property in Camera app
Fixes:
* Fixed screenUrl property in Camera app
* Fixed bug in Camera app with open/close
* ZMatter Binding: Thread credentials fixed
## 22.07.2024 v5.0.0
New features:
Improvements:
* Matter support added
* Zigbee: Meter cluster added (instanteneous and summation values)
* Zigbee: WindowCovering added
* Zigbee: isFailed added
Fixes:
* Fixed apps active state save problem
## 22.04.2024 v4.1.3
New features:
* Zigbee: add support for CC Temperature-, Pressure-, RelativeHumidity- Measurement, OccupancySensor
Improvements:
* Cleanup vDevs in the profile
* OpenWeather app
* if wingust will not be reported the value will be set to windspeed to avoid an empty value
* added "minutes" to label of refresh rate
* app descriptions and https
* added devices for using in automation
* changed options to pulldown
* added option for wind speed units
* added option for refresh selection
* added option for create temp/hum devices
* added option for create wind devices
Fixes:
* Ignore ZBee in backup/restore
* Update postfix.json (Philio PAN04, PAN06)
## 18.10.2023 v4.1.2
New features:
* Support for Zigbee clusters OnOff, LevelControl, ColorControl, IasZone and OccupancySensing
* Added Zigbee support to SwitchControlGenerator
* Allow custom IP reported from localIP.json file
Improvements:
* Reworked technology/bindingName/nodeId attributes of vDevs in Z-Wave/Zigbee/EnOcean/ImportRemoteHA/SwitchControlGenerator
* defaultConfigs updated, NotificationFiltering and NotificationEmail added
* Add Battery notifications to inbound notification
* Be more verbose in ImportHA
Fixes:
* Fixed double restart on zway.discover() exception
* Fixes in Zigbee app
* Fixed ZWave.prototype.applyPostfix error
* Fixed firmware-fault report
* Fixed wipeOut handler
* Typo in getMACAddress
* Update postfix.json
## 19.07.2023 v4.1.1
New features:
* Zigbee DoorLock support
Improvements:
* Rework of SmartStart UI
* HomeKit: Added Battery Service
Fixes:
* Fix missing flood sensor icon
* Fix probeType for motion
* Update postfix.json for FGS-213
* Fixed firmware update of Nth chip
* DummyDevice parseInt fix
* Set device isFailed based on lastCommunication value
* Correct logging of Notification channel not assigned to a user
* Fixed WB config to use Native module
* Fixed thermostat getCurrentTemperature
## 02.05.2023 v4.1.0
New features:
* Zigbee support added with Z-Wave.Me hardware
Improvements:
* MQTT: switchRGBW support
* Add Battery notifications to inbound notification
* Allow custom IP reported from localIP.json file
Fixes:
* Fixed double restart on zway.discover() exception
* Fixed firmware-fault report
* Fixed wipeOut handler
* registerNotificationChannel parseInt(user)
* Typo in getMACAddress
* Be more verbose in ImportHA
* Heating App: Don't set the temperature if it is not defined
* Postfix for Thermostat fixed
## 22.12.2022 v4.0.2
New features:
* Allow <deviceId:metrics:xxxx> in Notification Filtering
Improvements:
* Add URL to the HTTP error message
Fixes:
* Security restore mode
## 24.11.2022 v4.0.1
Improvements:
* Update postfix.json
## 01.11.2022 v4.0.0
New features:
* Full rework of Notification (Alarm) CC widgets: state events produces widgets, stateless produce hidden toggleButton
* Dummy device:
* Added Door lock, Blinds, Siren and Water valve to Dummy device
* User can generate access tokens now (for easy API integrations)
* Added HTTP API /ZAutomation/api/v1/devices/%dev%/%property% and /ZAutomation/api/v1/devices/%dev%/metrics/%property% to cimplify integration with third part APIs
* Postfix handling:
* vDev creation based on Configuration parameter with configVDev keyword
* vDev based on Notification Status
* Window Tilt pre-creation
* Added uuid, serial and mac fields to /system/info and /system/first-access API calls
Improvements:
* New API /encryptionKeys for S0/S2 key extraction (for Zniffer and PC Controller)
* Notification: improved icons
* Notification: Added support of eventParameter for Idle
* Allow disable packet log for slow systems: allow track & save, track only, disable (for slow hardware)
* Home name and Remote ID added to push messages
* Better e-mail description on device trigger
* HomeKitGate 2.2.2
* automaticaly add/remove Permanently Hidden devices
* minor fixes
* Added self.trigger in Easy Scripting
Fixes:
* HTTP API response for 0 and false fixed (before was null)
* Firmware Upgrade for target > 0 with target 0 not upgradeable
* AutoLock: minor
* Security app: arming/disarming schedule and many minor fixes
* Don't start paused instances after restore
* New users can set night_mode correctly
* Fixed profilesByDevice to also list devices in allows room
* Fix duplicates of Door and AC Alarms
* Fixed defered save (produced crashes on slow hardware)
* Set timezone
* Remove SoundSwitch Mute vDev on device deletion
* Fix error on logout for local user
* Fixed default .syscommands on Linux
* Fix RGB color set
* Fixed DeviceHistory check period
* Added meter events in notifications
## 02.04.2022 v3.2.3
New features:
* API for local token generation
* Allow disable packet log for slow systems or big networks
* Added uuid, serial and mac fields to /system/info and /system/first-access API calls
* HomeKitGate setting to allow remove phantom devices
Improvements:
* HomeKitGate 2.2.2
* More commands available in EasyScripting
* localGMT for getTime API
* More events on Websoket API (profile and room changes/remove)
Fixes:
* Error on logout for local user
* Security app fixes
* Fixed default .syscommands on Linux
* EasyScripting description fix
* SwithcControlGenerator problem with Basic
* Z-Wave binding stop abort on exception inside controller.device.remove
* RGB color set
* Remote Z-Way (ImportHA) RGBW control
* Don't set Time to itself
* Fixed DeviceHistory app
* Postfixes:
* Philio PAT13 Temperature Sensor postfix AutoOff on the Alarm button, set Alarm On
* Tion 4S SwitchMultilevel.data.interviewDone
## 29.11.2021 v3.2.2
New features:
* Websocket API improved. Now requires same token as for HTTP API
* Full rework of Security module
* Added Entrance group to allow delay for some sensors on armin and disarming
* Added support for scenes and buttons for arm/disarm/clear by button
* Added Arm condition and Arm failure action to allow checks for sensor state before arming
* Added ClearPacketLog ZWaveAPI
* Added duplicate field in packet log
Improvements:
* MQTTClient
* Added door lock support
* Added automatic re-connection
* Thermostats are now float, not integer
* Added Clock.Set() and TimeParameter.Set() daily at night to keep device at home synchronized
Fixes:
* Save defered saveObjects on Automation stop
* Fixed homekit-skip being ignored after restart
* Fixed bug with addTags not notifying subscribers
* Fixed Secure thermostat and Vitrum switches support
## 15.09.2021 v3.2.1
Fixes:
* Fixed missing third (immediate) parameter in saveObject
* Fixed bug in HomeKit with wipeout
* Fix local user devices list
## 24.05.2021 v3.2.0
New features:
* New MQTTClient app for exporting all devices to MQTT
* Added devices.wipedOut event
* Added manufacturer, product and firmware fields to vDev
* Added Appliance and Water Valve Notification types
* Adopted to new WebServer API with WebSocket Auth handler and new ws.push parameter with list of IDs to be notified with the event
Improvements:
* Added lazy write in saveObject function to save SD card and improve engine speed
* Full rework of applyPostfix to boost load process
* HomeKit:
* Full rework to fix rooms mix-up on Z-Wave app restart
* Made PIN static acoss restarts
* Added manufacturer, product and firmware information
* Security app:
* Disarm now works at any time, even if the sensor has triggered
* Added listing of directory in modulemedia API
* Improved speed with Date.now() instead of new Date().getTime() and new Date().valueOf()
* Removed test ws.push for incomingPacket (improved engine speed)
* Adopted the new lastExcludedDevice DH for proper cleanup on exclusion, zeno.unregister().
* Improved EnOcean.prototype.dataBind (like ZWave.prototype.dataBind).
Fixes:
* Fixed EasyScripting app UI slowdown
* EnOcean devices do not re-appear with same name and in same room after being added back.
* Fixed GetStatisticsData Z-Wave API and added ClearStatisticsData API.
## 24.03.2021 v3.1.4
New features:
* New EnOcean profiles added
* Added DecomposeRGB module
Improvements:
* EnOcean: periodical save of zddx, Made API non-public by default
* Improved Security App
* Improved Heating App
* ThermostatDevice: Allow calling handler from create event
* HomeKit support improved
Fixes:
* Fixed EnOcean duplicate devices
* Fixed error in NotificationFiltering when Channel is absent
## 09.02.2021 v3.1.3
New features:
* New EnOcean profiles added
* Added update() to EasyScripting menu
* Added SVG content-type to the list of loadable images
* Added ZWAYSessionCookieIgnore header to the auth API
* Added /devices/:v_dev_id/referenced API to show references to a vDev
Improvements:
* Logical Rules 1.5
* ThermostatDevice with float value
* Improved InboundNotifications module to allow some duplicate events. General rework
Fixes:
* Heating App: Correct start after reboot, correct handling of subsequent time slots, correct handling of rooms deletion and device load/unload
* Heating App: The schedule follows each other without reset to energy save, also when switching to another day. Without a schedule, energy saving is activated
* Fixed Network Reorganization infinite loop
* Removed SensorsPolling from default config - it blocks the queue and is not needed for most of customers anymore
* Removed empty customIcons
* Fixed a space before namespace that lead to this type of device not being displayed in the drop list
* Fixed that toogleButtons names were not displayed
* Sonos app cleanup
## 24.12.2020 v3.1.2
New features:
* Added SimpleAV to SwitchControlGenerator
* Added demultiplexer API call for HTTP GET request
* Added lastSeen and IP to sessions in user profile
* Added support for Window Tilt device
* Added support for Alarm AC Reconnect/Disconnect widgets
* FirmwareUpdate added support for 7th gen UZB/RaZberry
* Added WiFiCli API for Z-Wave.Me Hub to select WiFi network
* Added IP and RemoteID to first-access API
* Added profileName (hub name) to MobileAppSupportAPI
* HomeKit integration reworked and included in standard delivery
Fixes:
* Fixed problem with local URL in Camera settings
* Fixed battery error in EnOcean
* Added support for EnOCean GP
* Fixed NotificationChannelEmail not to report failure on mail send error
* Fixed HTTP API search to always match from the beginning
* Time driven item enabled in Heating widget
* Heating module. Update the list of rooms after deleting a room, frostProtection field
* Fixed moduleId in SwitchControlGenerator
* Do not logout permanent tokens
* Added CORS Allow-Control-Expose-Headers
* Added Authorization to Access-Control-Expose-Headers
* Default config.json updated
* Improved Alarm CC handler to fix error with undefined forEach
* Fixed FirmwareUpdate for target > 0
* Fixed Factory Reset on a controller w/o Z-Wave running (no zway object)
* Removed 'metrics:removed'
* Reset vDev to globalRoom if location does not exist
## 16.09.2020 v3.1.1
Fixes:
* Automation/Climate: current temperature always Comfort
* Added probeType to Http and Code devices
* Added probeType: "thermostat_set_point"
## 31.08.2020 v3.1.0
New features:
* New notifications style in Automation
* Added /notificationChannels and /notificationChannels/all API calls
* Added namespaces:notificationChannels:channelNameEx
* Added NotificationChannelEmail (replacement for MailNotifier), NotificationChannelSMSru (replacement for old NotificationSMSru)
* Adopted IfThen, SecurityMode to the new notification style
* Removed notifications from BatteryPolling - adopting new notifications style
* Removed modules MailNotifier (replaced by NotificationChannelEmail), Notification (deprecated) and NotificationSMSru (replaced by NotificationChannelSMSru)
* Added MobileAppSupport and NotificationFiltering.
* Added Zniffer SetPromisc API
* Improved Background RSSI measurement, made it more precise in time when polling
Fixes:
* Fixed EasyScripting Loop detected issue after an error
* Fixed NotificationChannelEmail userId saved as integer and not as string
* Temp fix of namespaces - to be reworked
* Added NotificationChannelEmail and improved NotificationFiltering.
* Fixed RSSI for sent packet for Zniffer
* Fixed bug with two dongles
* Cleanup. CIT code removed
* Fixed FW update via URL download
* Allow / in last argument in API router
* Network reorg fix
## 28.04.2020 v3.0.6
New features:
* EasyScripting app added
## 02.04.2020 v3.0.5
Fixes:
* Postfix Association wrapped in lastIncludedDevice check
* Full rework of NetworkReorganization
* Fixed incoming packet in RouteMap
* Fixed bug in ThemostatDevice
* Allow restore of Dummy Device value
* Added more error logging
* Added probeType, icon valve and siren.
* AutomationController.loadModuleMedia handles MIME types
## 20.01.2020 v3.0.4
New features:
* Google Home integration
* Added Sirent Notification/Alarm type for Goap Luxy
* Added SoundSwitch CC support
* Added debugPrintStack for easier debugging
* EasyScripting app
* Qubino Flush 1 Relay postfix
Fixes:
* Fixed Base64 bug with 0D 0A -> 0A. This issue resulted in corrupted images in rooms
* Fixed bug with Thermostat Operation toggle missing after inclusion until reboot
* Remove redirect_uri from profile and add uniq uuid to each profile
* Delete full profile on DELETE ZAutomation/api/v1/profile if only one token exists or only the token if there are others
* OAuth2 profiles metadata cleanup
* Moved devicesByUser, deviceByUser, locationsByUser and profileByUser to AutomationController
## 06.09.2019 v3.0.2
Fixes:
* location added to switchMultilevel and battery vDev types
* Version updated
* Fixed removal of old sessions
* fix undefined location
## 18.07.2019 v3.0.0
New features:
* Implemented Authentication Bearer for OAuth2.0.
* Permanent tokens
* Per device access for users added
* Making automaticaly permanent tokens with Authorization Bearer
* Add locationName attribure to vDev
* Thermostat commands improved
* HTTP redirect API added
* RemoveToken API added.
* Rework of profiles API
* Made session permanent and stored in config.js
* Added new bootloader to Z-Wave OTW
Improvements:
* EnOcean improvements
* Updated encryption function for TP Link Wifi Plugs
* Сapability to change level of sensorMultilevel and sensorBinary, useful for CodeDevice and HTTPDevice
* Support of postfix application for all devices of the same manufacturer
Fixes:
* Do not return 404 if no rooms granted to the user. Return empty0
* Save vDev probeType in config.json
* ThermostatSetPoint posfix fix
* Removed HttpOnly from the ZWaySession cookie.
* Duplicate ZWaySession in the header
* Timezone fixed for Raspberry Pi
* Fixed RGBW off oldColor save
* Added missing set of metrics:level for toggleButton
* Old tokens cleanup fixed.
* Do not apply Anonymous if there was and attempt to login (Auth Basic, Bearer or SESSID)
* Remove profile on OAuth2 failures
* Added WWW-Authenticate header to HTTP 401 reply
* Fixed bug in MobileAppSupport leading to error
* SwitchControlGenerator. Do not create device for CentralScene as it is handled in ZWave module
* Merge pull request #463 from RobertGebauer/master
* Update check of level to set: must be a number
* SHUI-546 Fix Info Widget
* SHUI-543 do not save unneeded instanceId in instance
* https://github.com/Z-Wave-Me/home-automation/issues/475
* update MobileAppSupport
* SHUI-521 add notification to scenes
* SHUI-534 fix silent and normal alarm
* SHUI-519 Support to compare 2 devices
* fix: getting new sid/session although the old session is still available,
* add default checks to VirtualDevice function for params tags, order, location, creationTime
* [SHUI-508] fix broken password reset
* [SHUI-507] Rules: Fix reverse function problem with 0
* Update check of level to set: must be a number
* Bugfix. Level "0" won't be set with previous check as !!level evaluates to "false" for level=0. As level "0" should be a valid level to set, the level is checked to be a number now.
AutoOff:
* Doorlock support for AutoOff module
DeviceHistory:
* externalAPIRevoke to DeviceHistory stop function added
IfThen:
* handling dimmer correctly in IfThen
NotificationSMSru:
* Huawei 3G/4G modems support
## 10.10.2018 v2.3.8
Features:
* remove uploaded room images
* new base modules added that combine or enhance functionalities of already well known modules, which are working without Alpca JS.
These new modules can be find and configured in SHUI under the Automation menu (gear wheel):
* Hazard Notification (combination from Leakage Protection and Fire Protection modules, ready for more)
* Rules (combination of If>Then (simple mode) and Logical Rule (expert mode) modules)
* Scenes (enhancement of Light Scene module)
* Schedules (enhancement of Scheduled Scene module)
* Security (refactored and scheduling enhanced)
* Heating (enhanced Climate Control module)
* transformation added that will optionally transform LogicalRules/IfThen into Rules, LightScene into Scene, ScheduledScene into Schedules instances and deactivate all source instances - so the transformation can be rolled back easily (using http://IP:8083/ZAutomation/api/v1/modules/transform/reverse will remove the transformation flag from all modules)
Changes:
* node id to vdev of zway devices added
* add remove location image api
* add prepareHTTPResponse function to AutomationModule.js
* ignore list of restore/backup functions refactored
* ZAutomation history API removed (now it comes from the module itself)
* storage function enhanced to remove not existing and cleared filenames from list
* add PNG and GIF to img type check
* QR-Code isn't stored on z-way-server anymore, it's generated on demand in UI instead (Devices > Mobile > Add)
* add restriction to QR code API - admin can request all QR codes, users can only request their own
* logical helper functions from Rules moved and centralized into AutomationModule.js, so also other modules can use them
* postfix.json updated (changed or added):
* added:
* Steinel XLED home 2
* Steinel Senor-Switched Outdoor LightScene
* Foxx Project Door/Window Sensor
* Foxx Project Flood Sensor
* Everspring/TechniSat RM1
* Heiman Smart Smoke Sensor
* Aeotec NanoMote One
* Aeotec NanoMote Quad
* Aeotec TriSensor
* TKBHome single/dual wall switch
* TKBHOME single/dual dimmer switch
* TKB Home Energy Plug In Switch
* Everspring Plug
* Popp Power Plug
* MCO Home Fan Coil Thermostat (2-pipe) V3.0
* MCO Home CO2 Monitor
* Qubino 3-Phase Smart Meter
* Qubino Smart Plug
* changed:
* Philio 4 in 1 Multisensor
* Philio Relay Insert Blind
* Philio Double Relay Insert 2*1.5 kW with Metering Function
* Foxx Project Smart Switch Gen5
* POPP Flood / Water Leakage Sensor
* TKBHome two channel switch TZX7
* TKB Plug Dimmer
* Qubino Smart Meter
* Qubino Flush Thermostats
* Qubino On/Off thermostat
* Aeotec Home Energy Meter - Gen5
* PAN16 Smart Energy Plug In Switch
* Everspring Lamp Holder
* Poly Control Dana Lock V3
* OOMI Door Window Sensor
* MCO Home - Water Heating Thermostat with humidity sensor
* MCO Home - Electrical Heating Thermostat with humidity sensor
* Sensative Strips Comfort / Drips
* Hank Flood Sensor
Fixes:
* ZWave v2.3.0
* update of failed status in zway vdevs fixed
* thermostat min/max fixed
* Public Z-Wave API with Expert UI fixed
* postfix update fixed
* Object.keys() error if cc.data is null fixed
* download URL of skins fixed
* Cannot select none image for room fixed
* icon upload and add uppercase extension (GIF,PNG,JPG,JPEG) support fixed
* missing transformation of main_sensor during update leads to indexOf undefined error - fixed
Modules:
* ZWave v2.3.0
* Gas Alarm (V7) 0x12 support added
* new alarm type - gas added
* to not polute the global namespace area a var was added to postfix logic
* Optimized a bit the F/W update code and added support of 40196 bootloader for upgrade UZB 5.07->5.27
* HTTPDevice v2.2.0
* enhancement: can set method GET/POST for update command
* helper fixed
* DeviceHistory v2.0.0
* new api HistoryAPI added (moved from ZAutomation and AutomationController to module)
* BindDevices v1.0.2
* sensorMultilevel support added
* MailNotifier v1.2.0
* change logic to handle also different mail adresses in e-mail outgoing
* BatteryPolling v2.2.0
* notifications support module added
* MobileAppSupport v1.2.7
* table of undefined bug fixed
## 23.03.2018 v2.3.7
Features:
* Added emulateOff postfix to Sensor Binary
* support for wifiplugs added (TP-Link HS100, TP-Link HS110, EDIMAX SP1101, EDIMAX SP2101)
* allow probeType postfix in ZWave module
* IP-address api added
Changes:
* Set thermostat value only if they are not equal * this will prevent ClimateControl app to set values twice
* add ip address to qrcode
* stored QR code is removed, now it is only produced in UI temporarely against successful authorization
* module categories "system" and "wifiplug" added
* rework the ZAutomation/api/v1/icons/upload API to return a name
* language files refactored
* postfix.json updated (changed or added):
* added:
* Popp Z-Weather
* Z-Wave.me Dimmer
* Danfoss Hydronic Controller 10
* Aeotec RGBW Bulb
* Aeotec Dual Nano Switch with Meter
* Aeotec Indoor Siren Gen5
* Aeotec Door Window Sensor 6
* Aeotec Dual Nano Switch
* Aeotec Water Sensor 6
* Secure 7 Day Programmable Thermostat
* Secure Temperature Sensor
* Secure Wall Thermostat with LCD Display
* Secure Z-Wave controlled Boiler Actuator (2 Channels)
* Secure Receiver with Relay SSR303
* Philio Smart Dimmer Socket PAD02
* Philio Double Relay Insert 2*1.5 kW with Metering Function
* OOMI Mote
* OOMI Plug
* OOMI Range Extender
* OOMI In-Wall Switch
* OOMI In-Wall Dimmer
* OOMI Colorstripe
* OOMI WATERSENSOR
* OOMI Multisensor
* Everspring Temperature and Humidity Sensor
* Everspring Wall Plug Dimmer
* Everspring ST812 Flood Detector
* Everspring SE812 Indoor Siren
* Devolo Alarmsirene
* Devolo Luftfeuchtemelder
* Devolo Wassermelder
* Devolo Bewegungsmelder
* Devolo Funkschalter
* Devolo Radiator Thermostat
* Devolo Rauchmelder
* Devolo KFOB
* Devolo Wall Plug 2.0
* TKBHOME single/dual dimmer switch
* SCHWAIGER * 4 in 1 Multi Sensor Outdoor IP43
* Fibaro Door/Window Sensor G5 * RU
* Fibaro Single Switch * 1*2.5 kW
* Fibaro Heat Controller
* MCO Home PM2.5 Sensor
* MCO Home Water Heating Thermostat with humidity sensor
* MCO Home CO2 Monitor
* MCO Home Glass Touch Switch (4 Buttons) British Standard
* MCO Home Glass Touch Switch (2 Buttons) British Standard
* MCO Home Glass Touch Switch (1 Button)
* MCO Home Glass Touch Switch (2 Buttons)
* MCO Home * Electrical Heating Thermostat with humidity sensor
* Sensative Stripe Multisensor Drip
* BeNext Wall Plug with Dimmer Function
* Hank Four-Key Scene Contoller
* Hank One-Key Scene Contoller
* Hank Flood Sensor
* Hank Motion Sensor
* Hank Smart Plug
* NEO Coolcam Door / Window Sensor
* NEO Coolcam Motion Sensor
* NEO Coolcam Siren
* Steinel Indoor Light
* Steinel Motion Sensor
* changed:
* Fibaro Double Relay Switch FGS-222
* Fibaro Door/Window Sensor G5
* Fibaro Dimmer 2
* Danfoss Hydronic Controller 5
* Devolo Door/Window Contact
* Aeotec Nano Switch 1 Relay
* Aeotec Range Extender 6
* Aeotec Door Window Sensor 6
* Aeotec Recessed Door G5
* Aeotec Multisensor Gen 6
* Qubino On/Off thermostat
* Qubino Flush Thermostat
* Qubino Relay Insert 1*2,3 kW
* Qubino PWM Thermostat
* TKB Plug Dimmer French
* WiDom Universal Double Switch
* Philio 4 in 1 Multisensor
* Philio PST02-5B Motion Sensor
* Philio Motionsensor
* Philio Relay Insert Blind
* Philio Double Relay Insert 2x1,5KW
* Philio PAN16 Smart Energy Plug In Switch
Fixes:
* Fix not working time-zone set via shui
* remote triggered on Z-Way startup
* fix setDefaultLang function
* allow probeType postfix in ZWave module
* save probeType in vdevInfo
Modules:
* TP-Link HS100 v1.0.0
* added to support this wifi plug
* TP-Link HS110 v1.0.0
* added to support this wifi plug
* EDIMAX SP1101 v1.0.0
* added to support this wifi plug
* EDIMAX SP2101 v1.0.0
* added to support this wifi plug
* Sonos v1.2.3:
* fixes
* icon changed
* MobileAppSupport v1.2.5:
* bugfix catches undefined-error occurred during adding first mobile device
* bugfix removing mobile device deletes LOCAL widget
* update IOS token
* remove devices manually
* ScheduledScene v2.2.0:
* can start scene many times in day
* defined default times: 00:00 and 12:00
* devices on new path, as example switch: this.config.devices.switches
* compatibility with old config
* Bugfix: Dimmers, Lock and scenes didn't run.
* IfThen v2.5.1:
* allow negative values for multilevel sensors
* LightScene v1.1.1:
* icon changed
* AutoLock v1.2:
* added switchBinary support and checkbox Don't send Lock command if doorlock already closed
* TamperAutoOff v1.1.0:
* fix to SETDATA
## 04.10.2017 v2.3.6
Changes:
* show more logs on ZWaveBinding error
* Refactored PacketLog to make it work faster and take smaller RAM/FLASH
* add location title in front of device names within module configuration dropdowns
* Modified MobileAppSupport and LogicalRules apps to push user defined notifications
* add rain and co sensor types
* updated underscore.js to v1.8.3,
* add auto installer for E-Mail Me instance (is added automatically after z-way f/w upgrade if e-mail under My Settings was set and no instance is already existing)
* E-Mail Me instance is added automatically during initial setup - e-mail is set during initial login
* add "zway_parsedPackets.json" to blacklists, to be ignored during backup / restore
* add topology restore flag to ZAutomation restore api
* add support for fan and siren (pull request #439 by maros)
* add removed flag to vDevs
* add vDevs of failed nodes will be marked as metrics.isFailed:true now
* nodes with WakeUp CC - except portable remotes - will be checked once a day if they are failed (no wake up during a specific interval)
* add filterByNode() and filterByCreatorId() to DeviceCollection.js
* add modules to support Technaxx TX65, TX66, TX67 cams
* add spanish translation
* postfix.json updated (changed or added):
* Popp 10 year smoke detector with siren
* Fibaro Door/Window Sensor G5
* Popp Thermostat
* Philio PST02-5B Motion Sensor
* Philio PAT02-5C Flood Sensor
* Foxx Project Range Extender
* Foxx Project Smart Switch Gen5
* WiDom Universal Double Switch
* MCO Home Fan Coil Thermostat (4-pipe)
* MCO Home Fan Coil Thermostat (2-pipe)
* TKB Plug Dimmer French
* Fibaro Door/Window Sensor G3
* Fibaro Single Switch 2
* Fibaro Double Switch 2
* NodOn Micro Smart Plug
* Aeotec Door/Window Sensor Gen5
* Popp Water Sensor
* Qubino Dimmerinsert 0-10V
* Aeotec Home Energy Meter - Gen5
* PAN16 Smart Energy Plug In Switch
* Eurotronic Spirit
* EVERSPRING ON/OFF Switch/Screw-In
* Aeotec Smart Switch 6
* Philio Motionsensor
* Fibaro Dimmer 2
* Aeotec Heavy Duty Switch
* MCOHome Thermostat MH7-WH-EU
* Aeotec WallMote Quad
* POPP Plug Dimmer
* Aeotec WallMote Dual
* TKB Plug Dimmer German
* Fibaro Keyfob
* Fibaro Wall Plug FGWPx-102
* Fibaro Universalsensor with Binary Input
* Popp Wall Plug Switch Outdoor IP44
* Popp Flow Stop
* Qubino Relay Insert 1*2,3 kW
* Vision Shock Sensor
* Popp Radiator Thermostat
* AEOTEC LED BULB
* Qubino RGBW Dimmer
* Vision DC/AC Power Siren
* Danfoss Radiator Thermostat
* Fibaro RGBW Module
* Vision Security Siren G5
* Qubino Weatherstation
* Domitech ZBulb
* Z-Wave.Me Wall Remote
* POPP Wall_C Forever - Wall Remote
* MCOHome Thermostat MH7-EH-EU
* Aeotec Nano Switch 1 Relay
* Aeotec Home Energy Meter - Gen5
* Aeotec Nano Dimmer ZW111
* Popp Z-Rain
* Aeotec Nano Switch
* Z-Wave.Me Funkwandschalter
* Fibaro CO Sensor
* Zipato Bulb 2
* Devolo Door/Window Contact
* Popp Solar Outdoor Siren
* Qubino PWM Thermostat
* WiDom Energy Driven Switch S/C
* Secure Water Meter
* Qubino Flush 1 Relay
* Qubinio Flush2 Relays
* TKB Home Wall Plug Switch
* MCO Home MH-S314 EU (UK)
* MCO Home CO2 Monitor
* MCO Home MH-S412
* MCO Home MH-S411
* MCO Home MH-S412 UK
* Philio 2-in-1 Sensor - Temperature and Humidity
* Philio 3-in-1 Sensor - Flood, Temperature and Humidity
* Qubino Roller Shutter Insert 2*1 kW with energy meter
* Qubino Dimmerinsert with energy meter
* Qubino Roller Shutter Insert 12-24V DC
* Philio Relay Insert Blind
* Aeotec LED Strip
* EverSpring Motion Sensor SP816
* Fibaro Door/Window Sensor 2
* MCOHome Thermostat MH7H-XH-EU
* TKB Home Power Meter Socket
* Everspring Door/ Window Sensor
* Philio Double Relay Insert 2*1.5 KW with Metering Function
* Danfoss Hydronic Controller
* Secure Z-Wave controlled Boiler Actuator (2 Channels)
* Secure Electronic Room Thermostat with Temperature Sensor
* Secure Temperature and Humidity Sensor
* Popp 10 year smoke detector
* Vision Door Lock with Handle
* Vision Garage Door Sensor
* TKB Digital Heating Thermostat
* Remotec IR Extender ZXT-120
* Fakro Electric actuator
* Everspring mini Plug
* Aeonlabs Minimote
* Aeonlabs Minimote
* POPP Keypad
Fixes:
* fixed LimitedArray class
* fix rssi output
* fix endless timeout entries of reorganization
* fix #442: Uncaught TypeError: Cannot read property 'filter' of undefined when getting notifications
* ZWave: fix not working set of old multilevel value
* ZWave: fixed that value and parameter not managed to 0
* fix not working Hide and hasHistory of elements is after z-way restart
* fix deleting room sensors from location is vdev moved to new location
* fix dublicated id's if instances are cloned
* limit max size of notifications to 2500. Old limit (5000) allowed file size over 1MB that resulted in complete cleared file after z-way restart
* fix d&d settings are lost after z-way reboot
Modules:
* DeviceHistory:
* remove listeners on stop
* fix notification bug in DeviceHistory app
* remove binary support from DeviceHistory app - it's handles by UI now with a better readable event list
* MobileAppSupport v1.2.2:
* modified to push user defined notifications
* add remote/local indentification
* LogicalRules:
* modified to push user defined notifications
* Camera:
* add screen URl for new camera view
* ZWave:
* add rain and co sensor types
* add replace smoke image with burglar image for burglar events
* fix not working set of old multilevel values
* fixed that value and parameter not managed to 0
* add isFailed flag to zway vDevs
* add SaveData to save once per hour
* MailNotifier v1.2.0:
* extend handler to send mails initialized by IfThen and LogicalRule
* add checkbox to allow using an alternative email address next to the preconfigured addresses in user settings
* LightScene v1.1.1:
* change icon type gesture to new type scene
* Sonos:
* Added previous and next song functionality to sonos module (pull request #446 by vuza)
* OpenWeather:
* Added clouds info to metrics:zwaveOpenWeather (pull request #438 by RobertGebauer)
* Added optional sunset / sunrise widget (inspired by pull request #229 from manyosit)
* If/Then v2.5.0
* allow use of mail and push notifications if condition is triggered
CIT:
* fix missing encodeURI
* send language keys for failed login feedback
## 28.07.2017 v2.3.5
Changes:
* saving of notifications / z-way data refactored
* now manged by LimitedArray Constructor
* notifications file will be cleared on startup if > 1MB - this should avoid z-way-server startup problems
* enable RSSI check only if implemented
* ZWave
* ZWave module specific files are now per instance
* Replaced global vars by local
* Better Z-Wave Binding restart code to try 10 times
* save old color for switchRGBW in vdev, save old level for switchMultilevel (probeType: switchColor_soft_white, _cold_white, _red, _green, _blue)
* load Cron as first module, to allow cronjob in ZWave module
* Update IntelHex2bin.js
* add app MobileAppSupport as system-app
* add email.me as system-app
* loadModuleLang refactored
* extract unnecessary files from backup file .zab to reduce size
* remove deprecated saveNotifications() function
Features:
* Support to show html page placed in folder MODULE_NAME/htdocs. You can open html page MODULE_NAME/htdocs/table.html from address: ZAutomation/api/v1/load/modulemedia/MODULE_NAME/table.html
* BE support for background room images
* Utils
* internet check added
* string to object parser added (and refactored in HA)
* location added to device-info notifications
* add periodically update of network statistics data
* BE support for Drag and Drop
* BE support for room main sensors (three sensors that can be assigned to room in UI)
* Modules
* Icons and Title name fix for modules which generate vDevs
* New constructor function LimitedArray added (lib/LimitedArray.js)
Bugfix:
* memory problems caused by huge amount of data
* fix zbw inquery #431
* UZB/RaZ upgrade fixes
* Fix updates of manufacturerId = 0 (Sigma Designs) products
* Fixed IntelHex converter
* Remove QR code update on profile meta data update
ZWaveAPI:
* PacketLog API added
ZAutomationAPI:
* add api to control ntp service
* certfxAuth api added
* move api's zwaveDeviceInfoGet and zwaveDeviceInfoUpdate out of ZWave module into ZAutomation API
* vendor db API added
Modules:
* HTTPDevice
* Added fields Content type and Data
* InbandNotifications
* fix undefined scale unit of device info log
* fix empty level in device-info notification
* expand device events to include default custom icon information
* refactored -> remove saving and polling
* ZWave
* inject zway config to ZWaveAPI
* expertsettings expanded + API changed
* zwaveDeviceInfoGet and zwaveDeviceInfoUpdate API's removed
* SmartLight
* add support for old Z-Wave.Me Dimmers
* IfThen 2.5.0
* Don't send On command, if device is already turned On, similarly for Off
CIT
* authentication added
* profile management added
* system/info API adjusted
* configuration added (ntp, wifi, CIT name, TZ)
## 18.04.2017 v2.3.4
Changes:
* NetworkReorganization API refactored
* widget CloudBackup instruction
Features:
* ZWave:
* Added support of probeType GAS and WATER
## 27.03.2017 v2.3.1
Changes:
* Added Z-Wave module restart after UZB/RaZberry upgrade
* box reboot refactored
* controller function - get instances by module name added
* Factory reset:
* add controller state check after SetDefault()
* exclude 'default' from skin uninstaller
* add null check to storage cleanup
* add notification
* saveObject():
* exclude null entries
* updateBackendConfig:
* add transformation that removes 'null' entries from storage content list
* User passwords converted to salted hash (sha512)
Bugfix:
* Fixed crash on title compilation in system with multiple dongles
* refactor error handling of broken or missing config.json / default-config.json
* Fixed bug with door lock status not updated
Features:
* Z-Wave MeterPulse CC support added
* QR code generation for login credentials added
ZWaveAPI:
* CallForALLNIF API added
* TestNode API added
* CheckAllLinks API added
* RSSIGet API added
* NetworkReorganization API added
* GetRorganizationLog API added
* sendZWayReport API added - sends a report including z-way data and last 1000 lines of z-way-server.log
* ZWave Backup API enhancement - optional up to latest 20000 lines of z-way-server.log can be added to backup package
Modules:
* NotificationSMS.ru
* Added filter for notification level
* PhilioHW
* improvements
* Correct value
* added
## 27.01.2017 v2.3.0
Changes:
* Added password field to all modules which use password field
* pull request #385 from pathec/patch-websocket
* notification api refactored:
* prepare redeem and delete of single or more notifications
* add possibility to redeem or delete already redeemed notifications (via request params)
* Postfix updated:
* Philio PST02-5B added
* Philio Vision PAT02-1A added
* sensorDiscrete support updated for all CentralScene devices
* fix debug.console
* deactivated by default
* JS/Run/controller.debug=true will activate console.debug output
* lib file descriptions updated
* more robust on config.json fault - will use default config.json instead
Bugfix:
* Do not update widgets if type is Invalidated
Features:
* add new device type 'sensorDiscrete'
* n-state vDev for CentralScene CC
* handles triggered scene in combination with their current key attribute
* skins api for skins ui feature support:
* update and install skins from https://developer.z-wave.me
* delete and apply skins
* reset skin
* custom icons api for custom icons ui feature support:
* update and install icon packages from https://developer.z-wave.me
* upload single icons or custom icon packages locally
* delete and apply icons
* icons can be applied depending on device type and there different levels or states
* cloud backup module for cloud backup ui feature support:
* only adjustable in SHUI under Configuration > Management > Backup & Restore
* needs deposited e-mail adress of user (Configuration > My Settings)
* restricted for admin users only
* could be triggered manually or automatically by configured schedule
* limited to 3 backups per box (remote id)
* a request for you cloud backups will verify your email against https://service.z-wave.me/cloudbackup/ and send you a response including accesses to your box backups
* this feature is OPTIONAL, so you can still use the already existing backup (Configuration > Management > Backup & Restore > Download backup to your computer)
* prepare set for timezone api
* prepare ZWaveAPI (ZWaveDeviceInfoGet/ZWaveDeviceInfoUpdate) for DB update of device data
* uploadModule.sh under automation/userModules added to allow upload of packed modules (tar.gz) directly from directory by ssh
ZWaveAPI:
* ZMEFirmwareUpgrade:
* Added a way to flash ZMEFirmware from local file
* ZMEBootloaderUpgrade:
* Added a way to flash ZMEBootloader from local file
* Added Access-Control-Allow-* headers
* new:
* ZWaveDeviceInfoGet ... GET
* ZWaveDeviceInfoUpdate ... GET
ZAutomation API:
* new:
* /notifications ... PUT/DELETE
* /notifications/:notification_id ... PUT/DELETE
* /skins/tokens ... GET/PUT/DELETE
* /skins ... GET
* /skins/install ... POST
* /skins/update/:skin_id ... PUT
* /skins/setToDefault ... GET
* /skins/active ... GET (ANONYMOUS)
* /skins/:skin_id ... GET/PUT/DELETE
* /icons ... GET
* /icons/:icon_id ... DELETE
* /icons/upload ... POST
* /icons/install ... PUT
* /system/timezone ... PUT
Modules:
* ImportRemoteHA 2.0.3
* add functionality to tag all remote widgets
* enhance url input to add ip adress only (with backward compatibility)
* bugfix: vDevs siblings (pull request #393 from xibriz)
* bugfix: inherit hidden or dectivated state
* bugfix: missing probeType
* IfThen 2.4.0
* add support for Color Switch (in targets)
* add support for type 'sensorDiscrete' (in actions)
* bugfix: doesn't decide if on/off was triggered - action is still fired
* ZWave 2.3.0
* add new device type 'sensorDiscrete'
* do not update vDev if type is Invalidated
* InbandNotifications 1.1.0
* add support for type 'sensorDiscrete'
* some refactorings
* Cron 1.0.0
* bugfix: initialization
* PhilioHW (POPP Hub 2)
* no_breath option and WPS LED indication
* breath off by default
* CloudBackup 0.1.2 beta
* added to automation/modules
* OpenWeather 1.0.1
* update open weather url's
* DummyDevice 1.0.1
* bugfix: NaN on switchMultilevel initialization
## 10.11.2016 v2.2.5
* some performance enhancements in CommunicationLogger and CommunicationHistory
## 21.10.2016 v2.2.4
Changes:
* pull request #372
* pull request #342
* update main.js (//--- Load 3d-party dependencies) for HomeGear support
* Postfix - (ZWave module):
* a lot of changes in internal postfix logic
* new configuration possibilities:
* change device name (new)
* change device icon (new)
* change node name (new)
* hide devices (new)
* deactivate devices (new)
* suppress device creation
* change configuration
* change CC data
* app switch controller support
* app major minor condition changed
* bugfix for fibaro smoke sensor postfix
* add postfix error messages, postfix.json updated
* Postfix - (ZWaveAPI):
* add expertconfig and api ExpertConfigGet + ExperConfigUpdate
* api's Postfix, PostfixUpdate, PostfixGet, PostfixRemove, PostfixAdd added
* ZAutomation API:
* allow also req type object as post object in login
* fix reload of initial getFirstLoginInfo call, add showWelcome entry - affecting (rebootBox, setLogin)
Modules:
* TamperAutoOff:
* added, workaround for devices that don't deactivate tamper sensor
* RoundRobinScenes:
* new param added in config
* LightMotionRockerAutocontrol:
* some bug fixes and improvements
* ZWave:
* Timing statistics changed according to new IMA data
* Added support for new bootloader and OTW to 6.70 SDK
* new sensortypes, seismic, acceleration x, y and z added
* IfThen
* add Thermostat, SensorMultilevel support
* BindDevices
* add thermostat support
* change name to Association
* Notification
* descriptions adjusted
* AutoLock
* pull request #319
Fixes:
* Z-Wave-Me/zwave-smarthome #190
* ZWave module:
* Fixed Communication statistics wrong timestamp
* Fixed non-working blind stop command
* fix for: Second Z-Wave module not generate a widgets #369
* bugfix: cannot read data of undefined / null (incomingPacket)
*RemoteAccess:
* bugfix: wrong ID after changing real ZBW ID.
* ScheduledScene:
* fixed bug after adding locks to the list of actions
## 12.07.2016 v2.2.3
Changes:
* Allowing Basic Authentication for Ajax Requests
* language keys updated
* dependency / instance handling:
* fetch undefined and failed instances to avoid error when they were adressed to global variable
* rework loaded singleton handling - in-/activate instance will not influence that list
* add new installed and added apps also to loadedModules list, to avoid there reinitialization
* flags of dependency error messages changed
* filtering in instantiateModules() changed
* remove pushNamespaces() for emit 'destroy'
* CHANGELOG, README, api doc updated
New features:
* Scene support for fibaro swipe added (4 scenes)
* Support fixes added for Philio devices: PST02-5C Door Sensor, PST02-5B Motion Sensor, PAT02-5C Flood Sensor, PSG01 Smoke Sensor
* /system/info api added
* LightMotionRockerAutocontrol module added
Fixes:
* bugfix non working increase / decrease command in device api
* bugfix non loaded modules - double load
* bugfix 'cannot read property meta of undefined' in module initialization
* minor refactoring of namespace generator
Modules:
* ScheduledScene: added locks support and send Action function
* PhilioHW: vDev added, batery charge timer
* ZWave: alarm probeTypes changed, tamper probe type added, renamed 'door' probe type into 'door-window'
## 11.04.2016 v2.2.2
New features:
* Reset to factory default (load default config, clear storage and userModules, set z-Way controller back to factory default, logout if succesful).
* Reset single device histories.
* Backup / restore of userModules added (Internet connection necessary).
* Welcome widget removed from default configs.
Fixes:
* CodeDevice typo.
* Callback execution error after calling a non existing/registered api.
* Added correct encoding in backup.
* Updating user profiles.
* Issues with set() of virtual devices.
* Too many bindings problem fixed for Alarm CC.
* More error messages internationalized.
Command Classes:
* Removed Basic CC from NIF, Secure NIF and Channel NIF to fit Z-Wave Plus (new in Z-Wave Plus specification).
* MaxCmd in MultiCmd changed to 3 (thanks to buggy Danfoss RS).
* Security Scheme Report value ignored according to spec change (new due to Z-Wave S2).
* MultiChannelAssociation bit address fixed.
* MultiChannelAssociation and Association are now limited by max together (sum of both groups) (clarified in Z-Wave specification).
* Association Remove group=0 fixed according to spec (clarified in Z-Wave specification).
New Command Classes:
* SimpleAVControl
Stability and security fixes:
* Better error handling of broken instances.
* Re-initialization of module refactored:
* for better error handling
* instances will be filtered and removed first
* the module reloaded and all instances created again
* user will get error output in events
* instances will not be recreated, if something has broken
* Version handling added, to check which installed App needs to be prefered (already preinstalled apps with higher version have priority).
* Description and instances entries of default configs updated.
* Don't backup/restore notifications.
* instantiateModules() refactored* depending on their dependencies.
* Refactoring creating user profiles.
* Send device in sleep right after inclusion (to save battery).
* Fix bug with keepAwake false on interview force.
API changes:
* Fixed Z-Way to start secure interview if Primary (no SIS) or if SIS itself.
* zway.SetLearnMode and controller.SetLearnMode are back to prior to v2.2.0 syntax with true/false parameter. NWI is handled under the hood.
* Object moduleCategories removed from config.
* Reverted this feature "Request NIF for devices that do not have a valid NIF after loading" (introduced in v2.2.1) due to conflict with Security.
* Added Function Class ExploreRequestInclusion (used internally in SetLearnMode).
* Setting probeType refactored (moved completely in to ZWave module).
* Remove old logic: Ignore SwitchBinary if SwitchMultilevel exists.
Apps:
* SecurityMode: event 'SecurityMode.alert' added by MarioGravel.
* LightScene: Lock support added + minor enhancements.
* RoundRobin: update on itself to allow catching own events.
* RemoteAccess: refactored.
* DeviceHistory: refactored (new handling for scenes, switchControl added).
Debugging tools:
* Debug function zway_fc_application_command_handler_inject (zway.InjectPacket) to inject packet from any device like incoming from Z-Wave.
* Debug zway.SendDataSecure to allow sending commands using Security CC (like zway.SendData but with security forced).
* Default config in automation/defaultConfigs/config.json for factory reset. Can be used to revert to factory default after screwing up.
## 18.02.2016 v2.2.1
UI:
* Enhanced display on mobile devices and tablets.
* Added the ability to customize the device from Devices/Manage.
* Backup and restore.
* Redirect to the APP detail after module instalation.
* Rating, download counter and comments of the Apps.
* Improved modal windows and dropdowns.
* Remember me checkbox on the login page.
* Sorting Elements by title, newest....
* Added icon to deveices list in Events.
* Added stop button to blinds.
Expert UI:
* Network/Controller: Firmware Update page for RaZberry.
* Size of UI optimized.
New features:
* Request NIF for devices that do not have a valid NIF after loading.
Fixes:
* Cannot add email address to user #90
* Climate Control widget displays the correct values.
* List elements error #82.
* Can not install user module from store #87.
* Fixed redirect after post/put a local app.
* Elements are completely refactored.
* Replaced Bootstrap modal windows and dropdowns with Angular.
* Fix zway.devices[X].instances.length problem
Stability and security fixes:
* Fixed SegFault on non-existing CC inside MultiChannel.
* Fixed rare packet buffer corruption.
* Fixed devices data loss on bad data from UZB/RaZberry.
* Backup/restore problems fixed.
* Mark CC in channel as secure if this CC on instance[0] is secure
API changes:
* Authentication process with Secure Login.
* Replaced http protocol with https for external APIs.
* Enable SIS on secondary controller after exclusion
## 12.12.2015 v2.2.0
UI:
* Initial page forces to change default password and add email for password recovery. Password recovery by mail.
* New design for RGB color picker.
* Redesign of Dimmer Element. Has now 3 buttons for off, on/last state, on/full state.
* Events can now be filtered on any device.
* New design on Setup Menu, all Management functions are in single menu element shortening the menu.
* New design for device management. EnOcean UI is only shown if Enocean is active, Setup and Management for all different technologies is unified now.
* Z-Wave management now allows to remove Z-Wave device, either by Exclusion or by Removing a failed node.
* New Info Page gives valuable data for support.
* Dashboard Message improved if dashboard is still empty.
* New design for all elements. They now show the room they are assigned to plus measured values are much larger.
* Description of the bug report function added.
* Menu icons for Elements and Rooms are twisted.
* Whole new design of App store.
* Now App store is open for third parties.
* Allow update and delete of apps.
* Apps are now grouped by theme.
* Its possible to access private apps using token string.
* New section "featured" for the most important apps.
* Newly created elements are color marked to find them better.
* New Icons for Thermostats and different other sensor values.
* Elements are now ordered by name.
* Plenty of changes to adapt to different mobile device screen sizes.
* All devices now belong to a room. There is a wildcard room for devices not assigned yet.
Expert UI:
* Showing current license in Expert UI.
* Description of different colors in routing table.
* Complete redesign of Association Settings page.
* Redirection to login page if accessed directly without login.
New features:
* Added support for WebSocket client and server (not on all platforms yet).
* notification2ext modules added to save notifications on external flash.
* Asynchronous DNS resolver for http and sockets not to block JS (not on all platforms yet).
* Support SendData to broadcast (node 255).
* Added JS functions for AssignReturnRoute, AssignSUCReturnRoute, DeleteReturnRoute.
Fixes:
* Restore functionality fixed. Make sure to update bootloader and firmware to 5.04 on UZB and RaZberry before running restore!!!
* Conforms with latest Z-Wave Plus updated specification.
* Fixed missing scales problem for Multilevel Sensors.
* New scales added for Multilevel Sensors.
* Fix incomplete read issue in system() API function.
* Print module js file:line info when compilation error occurs.
* Fixed SerialAPI AddNodeToNetwork and RemoveNodeFromNetwork callback mess. Need firmware 5.04 on UZB and RaZberry.
* ReplaceFailedNode restarts full interview including Security interview.
* ZMEFreqChange current frequency detection bug fixed.
* Compatibility: allow setTimeout(fn, 0) which is used sometimes for deferred callbacks.
* Fixed output of SDK version name of devices and RaZberry/UZB.
* Remote Access rare problems fixed.
* All device are now grouped by namespaces to allow easy selection in App settings.
* OpenWeather now with API Key (according to changed of the service).
New Command Classes:
* MultiChannel v4, MultiChannelAssociation v3, Association v2 support
* ThermostatSetPoint v3
Stability and security fixes:
* More stable interview with Security on slow hardware
* Few potential crash situations fixed
API changes:
* zway.SetLearnMode and controller.SetLearnMode parameter can now be 0, 1 and 2 to support NWI Learn Mode. See docs.
* lastExcludedDevice is now updated AFTER device complete removal and is now also updated in RemoveFailed success callback.
## 04.09.2015 v2.1.1
Command Classes:
* MCAv3 implementation added.
* Updated CC implementation to the latest Z-Wave standards.
New features:
* Frequency request from Z-Wave.Me stick and RaZberry.
* Authentication added to all HTTP requests.
* Device specific fixes applied to device inclusion.to fix minor non-interoperability.
* Add updateOnAction and skipEventIfSameValue flags to HTTPDevice and CodeDevice
* SwitchMultilevel value is repeatedly requested every 2 seconds until value stops changing.
Fixes:
* loadObject problem fixed on Windows.
* getsockname (detection of own IP) fixed.
* Allow named access to command classes even without public functions (like CentralScene or Security).
* Fix inf and nan problem in JSON* now they are null.
* CentralScene added to controller default to allow catch them on controller.
* zway_queue_inspect() call made public.
* NoOperation now is now issuing an isFailed after undelivered packet and it is sent only once to battery devices (to mark as failed).
* Many fixes in EnOcean.
* Show only devices from allowed rooms (don't show unallocated devices),
* Fixed authentication problems with find.z-wave.me and local user.
* Removed status field from modules.
* Fix devices update problem in ZAutomation API.
* Warning (255) battery values mapped to 0
* Fixed Thermostat F scale problem
* LogicalRules Switch on/off action fixed
* Sonos, RGB, SecurityMode modules fixed
UI:
* Easy installation of new modules from online store.
* Thermostats and A/C widgets fixed.
* Many improvements in Smart Home UI and Expert UI.
## 28.06.2015 v2.0.1
Command Classes:
* MultiCmd MaxNum changed to 6
New Command Classes:
* MultiChannel v4 support
Stability and security fixes:
* Don't allow to call secure commands unsecurely.
* Fix Security Scheme Inherit.
* Fix timers issue when clock is adjusted.
* Fix some non-blocking socket issues in sockets.
* Check if device still exists after SendData callback.
* Prevent segfault when unsubscribing data holder callback from within itself
* Restore function on 6.51.03 works again
New features:
* Add remote peer info in WebServer.
UI:
* Remote access management added to Home Automation UI.
* Removed UI selector page, access is possible via direct link or Info Widget
## 29.05.2015 v2.0.1-rc33
Command Classes:
* Make Basic CC mandatory in Secure NIF too
* MultCmd set maxNum in Defaults.xml.
* Ignore supported reports for already interviewed
* SensorBinary/SensorMultilevel command classes (to fix phantom sensors).
* Add 10 sec grace period for SensorMultilevel v1-4 when new sensor types are still accepted.
* Support rfStateCap == 0 in Protection CC to correctly handle devices with no RF protection.
* Update event type parent DH for Alarm/AlarmSensor CC when receiving event reports.
New Command Classes:
* MultiChannel v4 fallback support (supported as v3).
Fixes:
* Fix timers and queue hangs issue when clock is adjusted too much.
* Fix Security scheme inherit logic.
* Fix Alarm v3 event type mask bug.
* Make saveObject() atomic.
* Fix Version CC segfault on version change
* Workaround for devices not removing Security from NIF in usecure inclusion.
Home Automation:
* Notification CC (Alarm v3) renders vDev
* Added Sonos and GlobalCache modules
* Users management and authentication added
New features:
* Made queuing a bit faster: do not NACK job when received SOF while awaiting for ACK, CAN problem fixed.
* JavaScript sockets module now supports non-blocking, asynchronous, multicast, broadcast and reusable sockets.
* JavaScript XML module namespaces support added in findOne/findAll.
* Added possibility to write own V8 extensions. Sample code here: http://razberry.z-wave.me/fileadmin/modsample.tgz
* Added processPendingCallback() call in JS code (to keep callbacks working while handling slow code in JS).
* Add UZB driver to Windows installer
UI:
* Removed Z-Way HA UI and Blue UI.
* Made new Smart Home UI as default HA.
## 03.02.2015 v2.0.1-rc15
Z-Wave Plus certified for US (Certification Number ZC10-15010005).
Support for UZB1 added. Require additional license from license.z-wave.me (not finished yet !!!!!!).
From now Windows is maintained as well.
Command Classes:
* FirmwareUpdate progress added.
* ThermostatSetPoint v3 thermostat modes added.
* ManufacturerSpecific v2 implemented.
New Command Classes:
* MeterPulse
* BarrierOperator
* Hail (used to bypass Lutron patent in some old US devices).
New features:
* Added crypto module to JavaScript: crypto.sha256() and others (see docs).
* Added sockets module to control third party devices via TCP and UDP (like Global Cache or Sonos).
* Allow multi-level form serialization in http.request().
* Add support for HTTP compression of JS responses.
* Serve first pre-gzipped static files if present.
* Sort devices with equal probing score alphabetically (in GuessXML).
Fixes:
* Queueing made more stable. Sleeping secure devices managed better.
* Interview made more stable:
** does not restart on Wakeup Notification from the device.
** continue interview on device wakeup.
** fixed problems with not all sensors rendered for SensorBinary V2.
* Restore fixed on UZB1 and 5th gen RaZberry
* Fixed issue with detached threads in http module.
* Proxy can handle URLs with &. Used for some cameras.
* Adopted latest changes in Apple HomeKit.
* Encoding problems with Unicode in JS API.
* Fixed problem with CRC16 and MultiCmd rendered due to corrupted packets from RF.
* Fixed problem with wrong version of Command Class rendered during interview.
* Fix problems caused by ether noise: ignore supported reports for already interviewed command classes.
* Stability fixes.
Home Automation:
* Support for AlarmSensor (used in Fibaro devices and some others) in HA UI.
* Logical Rules module can be triggered by scenes (not only by device change as previously).
UI:
* Localization added. You can translate Z-Way Homa Automation in your language in automation/lang/ and automation/modules/*/lang/.
* RGB (SwitchColor CC) added to Z-Wave binding
* Many small improvements in Expert UI
* Small fixes in HA UI
API changes:
* SwitchColor CC now have new dataholder structure (same as other CCs with scales and types)
* Added _ prefix to functions from z-commons library bytes_to_* and *_to_bytes to minimize risk of overload by user functions.
* WebSocket API changed: event type added. Server can filter events based on this type before sending to clients.
## 21.11.2014 v2.0.0
Z-Wave Plus certified for EU (Certification Number ZC10-14110009).
Z-Way can work as primary and as secondary controller (to work with other Z-Wave controllers).
A lot of improvements and stability fixes.
Command Classes:
* SensorMultilevel will not create phantom sclaes anymore
* Alarm v2 fixed
* MultiCmd adopted to fix DLC 13 problem
* Security implements inclusion timers for secure inclusion
* SwitchBinary and SwitchMultilevel can now work as device
* NodeNaming UTF16 fixed
* MultiChannel Find Instance implemented
* AGI bugs fixed
* Association/MultiChannelAssociation autoconfig logic changed
* PowerLevel support added
New features:
* Completely new software structure
* HomeKit preliminary support. Waiting for apps in AppStore
* Proxy implemented in the engine to pass thru WebCams and other content via find.z-wave.me
* Websockets support
* Syslog logging support added on Unix/Linux platforms
* Add diagnostic messages in case of data access without a lock (for libzway users)
* Support for new 5th gen UZB dongle and RaZberry (AutoFlashAutoProg, NMV, RFPowerLevel, SendTestFrame functions added)
New Command Classes:
* Proprietary for few devices on the market using it
Minor changes in the API:
* FirmwareUpdate dataholders renamed
* New controller state Resetting assigned during reset to factory process (controller.data.controllerState)
* Replace python-style DataHolders type names in ZDDX and JS:
** "NoneType" changed to "empty"
** "str" changed to "string"
** "str[]" changed to "string[]"
* Data Holder JS property name is now hidden and is not returned in JS output neither in /ZWaveAPI/Data/
* Data Holders C API changes: all "zway_data_*(zway," should be changed to "zdata_*("
* Changed format of config.xml file and command line parameters. Now all Z-Wave related data moved into appropriate JS module
* Functions loadJSON(), saveJSON() and similar moved to fs.loadJSON(), added fs.load() to load any file as string
Fixes:
* SUC/SIS handling enhanced
* Works perfectly as secondary controller
* PowerLevel full support on 5th gen dongles/RaZberries
* AddNodeToNetwork and RemoveNodeFromNetwork cancel hang fixed
* Max packet size handling enhanced
* Answer-as-requested policy implemented to conform Z-Wave Plus (for Security/MultiCmd/CRC16)
* zway.bind with EnumerateExisting fixed
* RemoveFailedNode and ReplaceFailedNode timeout rised
UI:
* New Expert UI. Old Blue UI kept as second option.
* Communication statistics added for more network debugging
* New HA UI improved, more modules added
About New Expert UI:
* More installer friendly
* Works perfectly on tablets
* Multi Channel Associations can be set in a user friendly way like simple Associations
* Communication Statistics for advanced analysis of network stability
* Map removed from this UI
* Firmware Upgrade support
WebServer features:
* It is possible to run many WebServers on different port with different API and handlers
* Proxy support: webserver.proxify(url, target, [user, passwd]) creates transparent redirect
* WebSockets clients can receive notification from WebServer via webserver.push(obj) method
## 26.07.2014 v1.7.2
Fixes and improvements:
* Fix auth parameter in http.request()
* Small Z-Way C core fixes and improvements
* MeterTableMonitor historical data storage fix
* Fix various minor issues in JS code
* Fix DH deletion notification for array values
* Fix memory leak in ZXmlDocument.findOne() and deviceTypeString
* HTTP module: force adding content type for POST requests if not specified
* Do not perform url encoding on http headers
* Added optional timeout (ms) parameter to ZHttp
* Correctly output JS functions as strings when returning from /JS/Run/func
* Fix data holder value setter to work for both "dh.value=xxx" and "dh=xxx"
New features:
* New UI selector
* Function classed for NVM operations for 5th gen dongles (for 6.5x SDK)
Command Classes:
* CentralScene: respond to supported get, return number of scenes from config
* Time: respond with real time offset information, handle time offset report
* ClimateControlSchedule: added Override Get/Set
* Add UserCode SetRaw method for devices pretending user code to be binary.
Minor change in the API:
* givenName added to device dataholder to store names in Expert UI (for future use)
* User Code data holder type now depends on actual code data (bnary or string)
* Always read user code payload if present (even if status is 0)
## 18.06.2014 v1.7.1
Fixes and improvements:
* Fix memory leak in http.request().
* Fix issues with too many threads created by many http.request().
* Make v8 debugger not to crash on ZXmlNode objects and on CC access.
* Minor fix of UserCode clear.
* Delivery statistics not recorder for encapsulated packets (only for physicaly sent).
* z-cfg-update can now convert from very config starting from v1.2.
* Improve experience with modern secure door locks inclusion.
* Limited callbacks count on DataHolder from JS not to overkill the server from JS and to easily find bugs in JS code.
* DataHolder callback with notifications for child events fixed.
New features:
* Experimental: v8 remote debugging!
Debugger:
The debugger is enabled by setting V8_DEBUG environment variable and uses port 8183 (base port + 100).
Then you can connect either with d8 (./d8*-remote_debugger*-debugger_port=8183) or with node-inspector*-debug-port 8183.
## 23.05.2014 v1.7.0
Fixes and improvements
* Check connectivity button fixed (NoOperation is not removed by Force Interview now).
* Mark Failed Node and Remove Failed Node not always working fixed.
* Blue UI fixes.
* A lot small bugs fixed...
New Command Classes:
* PowerLevel
* Version V2
* FirmwareUpdate
* ZWave+ Info
* AssociationGroupInformation
* DeviceResetLocally
* CRC16
* SwitchColor
* CentralScene
Minor change in the API:
* Controlled only Command Classes are now also saved on server stop and loaded on starup. Allows to bind to dataholders on controlled Command Classes.
* Added .supported datholder to all Command Classes data.
* Battery level 255 is now mapped to 0 (so, 255 will be never seen from now).
* Defaults.xml format changed!!!
* xxxxxxxx-DevicesData.xml changed a bit. Added z-cfg-update utility to update xxxxxxxx-DevicesData.xml to the new format.
* Timeouts rised for AddNodeToNetwork and RequestNodeNeighbourUpdate functions.
New features:
* Log JavaScript files and lines on exceptions for easier debug.
* Log possible exceptions in HTTP.
* Open serial port exclusively to prevent multiple Z-Way or some other software running in parallel.
* Added secureInclusion for unsecure interview (set it to false to include device insecurely)
* Keepalive enabled in Z-Way HTTP server
* Z-Wave+ Associations made only to Life Line group #1
* SensorMultilevel new types implemented.
* Blue UI ZDDX Create button.
* Remote Access and 8084 port for maintainance added to the distribution.
## 13.02.2014 v1.5.0-rc1
New features:
* XML parser in JavaScript with XPath (ZXmlDocument JS object).
* HTTP network operations implemented in JavaScript (http JS object).
* Basic, SwitchBinary and SwitchMultilevel Set events to controller now have srcInstance and srcNode to distinguish sender.
Fixes and improvements:
* Works now on new Raspbian based on 3.10.x kernels too.
* Better network management for large networks.
* Minimize packets flow with Secure nodes (might not work with ald Kwikset doorlock).
* Better packet flow for sleeping secure devices.
* Alarm and UserCode CC minor fixes.
* Basic->SensorBinaryV1 mapping fixed.
* Backup/Restore SDK names fixed.
Minor change in the API:
* bind() now returns just bound function instead of undefined
* Basic dataholders lastset and mylevel removed.
* SwitchBinary level dataholder made boolean.
## 23.10.2013 v1.4.1
New Command Classes are implemented:
* Alarm CC V1-3 supported (no expert UI yet).
* MeterTable CC V2 supported (no expert UI yet).
Minor change in the API:
* SwitchBinary Set value is now boolean.
New features:
* Communication statistics gathered in devices[N].data.lastPacketInfo
Fixes:
* Sensor Binary fixed to receive changes from devices
* Some fixes in the blue UI
* Minor bug fixes
## 24.09.2013 v1.4
All available UIs are shipped included now. Go to /index.html page to select a UI:
* future UI (in development)
* current UI (old blue for experts)
* old jQuery mobile UI
New Command Classes are implemented:
* ApplicationStatus
* DoorLockLogging
* Indicator
* Meter v3
* Protection v1 & v2
* ScheduleEntryLock
* SensorBinary v2
* SensorConfiguration
* ThermostatFanMode
* ThermostatFanState
* ThermostatOperatingState v2
* TimeParameters
Home automation engine poject started (code in development, stored on https://github.com/Z-Wave-Me/home-automation)
Important API changes:
* loadJSON function added to API to allow load a file from program folder.
* Command Class SensorBinary data tree has changed. Now it contains sensor types like SensorMultilevel.
* SwitchMultilevel commands SetWithDuration and StartLevelChangeWithDuration are removed (Set and StartLevelChange should be used).
* SwitchMultilevel Set/StartLevelChange are always with duration in C.
* New ChildCreated event on dataholder added to trap new child node cration.
* New JavaScript methods: fs.list(dir) and fs.stat(file).
Fixes:
* ThermostatSetPoint, SensorMultilevel, Meter UserCode improved, some minor problems fixed.
* Full RF power during inclusion/exclusion is restored.
* Thermostat temperature C/F conversion fixed (mostly for US products)
Other features:
* New V8 engine is used for better stability and performance. The code was reworked a lot to become faster and more stable.
* Better logging with log levels (check config.xml).
NB! You need to force interview for all devices with SensorBinary and SensorMultilevel Command Classes.
Go to Device Configuration tab, toggle Expert mode (bottom right corner) and press Force Interview under Advanced actions cut link.
NB! After backup & restore process it is recommended to re-install Z-Way (using same command as to install it).
Otherwise it might not run next time after restore. (due to old config/Defaults.xml comming from old package).
## 19.05.2013 v1.3.1
New feature:
* Backup/Restore implemented. You can restore config files only or full Z-Wave topology.
## 17.05.2013 v1.3
New features and improvements:
* Full Security support with all certified locks (tested with Kwikset, Vision Security, Yale)
* Communications with Danfoss living connect tuned to stop battery drain by the thermostat (full re-inclusion is required to heal Danfoss living connect!).
* Better performance and memory footprint. We have made major refactor of our Z-Wave engine to make it faster and more memory efficient!
* Better queue handling for failed nodes preventing them from blocking the full queue. Now even unpowered or failed devices in your network will not affect user experience anymore.
* Added public method in C and JS API to check if command class is supported.
* Release information stored in Z-Way library.
New Command Classes:
* MultiChannel v3
* SceneActivation
* SceneControllerConf
* SceneActuatorConf
* Clock
* Time
Bug fixes:
* fix of system() call in JavaScript
* UserCode.Set()
* crash on broadcast Basic.Set
* potential problems with Add/RemoveNodeFromNetwork/ControllerChange/CreateNewPrimary/RemoveFailedNode Function Calls.
Changes in frontend:
* Translations to Spanish, Russia, Deutsch. We will appreciate your help to translate our UI to your language.
* Thermostat UI fixed.
Major changes in software design:
* devices[x].data.ZDDXMLLang and devices[x].data.ZDDXML removed: client must load the file called devices[x].data.ZDDXMLFile.value from the backend and parse the language content.
!NB Some devices might require interview force to show properly Expert Commands and configuration parameters!
## 29.03.2013 v1.2
New Command Classes:
* SenorMultilevel V5 support (NB! Structure of SenorMultilevel data holder changed for all versions of this Command Class)
New features:
* /ZWaveAPI/Run/[...].data.[...] now returns dataholder tree in same structure as /ZWave/Data/[...]
* shortcuts for CCs on device and instance in JS syntax: you can now write devices[5].Basic.Set(255) instead of devices[5].instances[0].commandClasses.Basic.Set(255)* both "commandClasses" and "instanes[0]" can be omitted
Fixes:
* Unnecessary Command Classes on devices removed
* Queue handling after restart
* Line endings in ZDDX that caused UI to stop working
* More sanity checks to prevent crashes
## 04.03.2013 v1.1
New features:
* Z-Wave secure door locks support
New Command Classes:
* Security
* DoorLock
* UserCode
New methods in JavaScript to make more fun with JS. See documentation on documentation RaZberry page.
Minor bug fixes.
# Release 1.0.1 (in progress)
* Removed `actions` and `metrics` properties from the `module.json` of all modules.
* Module classes automatically loaded to the controller. Removed `modules` property from the `config.json`.
* Introduced `skip` property to the `module.json` which instructs AutomationController to skip module class loading.
* Introduced `autoloadPriority` property to the `module.json` which determines automatic module instantiation order (lower** the sooner).
* Introduced `caps` property to the Virtual Device which allows to list device capabilities.
* Widgets moved to the new CommonWidgets module. Creation and registering custom widgets made possible.
* Module's templates and htdocs folders now resides in ./templates/<ModuleName> and ./htdocs/modules/<ModuleName>
* `config.json` existence checking on startup
* New configuration setting `vdevInfo` allows to set human-readable device names and tags
* Introduced icon VDev metric
* Introduced `VirtualDevice.deviceTitle` & `VirtualDevice.deviceIcon` methods
* VirtualDevice now requires `init()` to be called after instantiation
* Widget's htdocs and Module's templates moded outside of the module's folder (for all modules)
* Introduced .caps vDev's property which contains device extended capabilities tags (take a look at BatterPolling module)
* Introduced className property in the widget's meta-description which allows to set custom widget className (essential to custom widgets)
* UI is now capable of showing widgets created and registered by the customer
* Renamed AutomationController.widget* to AutomationController.widgetClass* and changed widget subsystem behaviour to resolve ambiguity
* /ZAutomation/api/widgets/ now replies with widget classes definitions instead of widgets itself. Latter exists and creates only on the client-side, but exact widget's class names described in a vDevs.
* UI Dashboard refactored according to widgets subsystem changes
* Fixed bug with loading ZWaveDoorlockDevice. DoorlockWidget implemented.
* Added `exact` command to the MultilevelSwitch
* SwitchBinary & SwitchMultilevel now has equal deviceType (switch) and different deviceSubTypes
* Added tags and locations subsystems
* Added support multi-profiles
* Added control widgets position
* Refactored API (devices, locations) and added new methods (modules, profiles)
# Release 1.0.0
(initial)
================================================
FILE: README.md
================================================
Z-Way Home Automation Engine
====================================
# Introduction #
<a href="https://gitter.im/Z-Wave-Me/home-automation?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge">
<img src="https://badges.gitter.im/Join Chat.svg" alt="Join Chat on Gitter">
</a>
## Available WebUI's:
* Smart Home UI: https://github.com/Z-Wave-Me/zwave-smarthome
* Smart Home Lite UI: https://github.com/Z-Wave-Me/z-wave-smarthome-lite/tree/mobile
* Expert UI: https://github.com/Z-Wave-Me/ExpertUI
## Pull Requests
For a better integration during running developments, please use [Home Automation develop branch](https://github.com/Z-Wave-Me/home-automation/tree/develop) for your pull requests.
## Complete Documentation:
* [Z-Way Manual](https://z-wave.me/manual/z-way)
## Home Automation Documentation's:
* https://github.com/Z-Wave-Me/home-automation/wiki
## API Documentation:
#### ZAutomation:
* http://docs.zwayhomeautomation.apiary.io/ (still in work)
## Issues, bugs and feature requests are welcome:
* [Home Automation issues](https://github.com/Z-Wave-Me/home-automation/issues)
* [Smart Home UI issues](https://github.com/Z-Wave-Me/zwave-smarthome/issues)
* [Expert UI issues](https://github.com/Z-Wave-Me/ExpertUI/issues)
* [Z-Way core issues](https://github.com/Z-Wave-Me/z-way-issues/issues)
## Available Z-Way Server Downloads:
* https://storage.z-wave.me/z-way-server/
## Current changelog's:
* [Home Automation changelog](https://github.com/Z-Wave-Me/home-automation/blob/master/CHANGELOG.md)
* [Smart Home UI changelog](https://github.com/Z-Wave-Me/zwave-smarthome/blob/master/README.md)
* [Expert UI changelog](https://github.com/Z-Wave-Me/ExpertUI/blob/master/README.md)
* [Full Z-Way changelog](https://storage.z-wave.me/z-way-server/ChangeLog)
## Z-Wave.Me - Developer Console (App Store)
Create an account and upload your own Z-Way home automation apps, share them with a special group or verify them for public access.
* https://developer.z-wave.me/
There are also some How To's about creating own apps for home automation and what to be considered during creating virtual Devices.
* [Help and How To's](https://developer.z-wave.me/?uri=help)
* also checkout the tab Upload-Process to see how it works
You can also find a list of all [currently published apps](https://developer.z-wave.me/?uri=public#/web/apps)
## Discussion platforms:
* https://forum.z-wave.me/ (discussions available in en/de/ru/fr/it/cn, use General or RaZberry forums)
================================================
FILE: StorageProvider.js
================================================
/*** Main Automation storage module *****************************************
Version:
-------------------------------------------------------------------------------
Author: Stanislav Morozov <r3b@seoarmy.ru>
Copyright: (c) ZWave.Me, 2014
******************************************************************************/
// ----------------------------------------------------------------------------
// --- ZAutomationStorageWebRequest
// ----------------------------------------------------------------------------
function ZAutomationStorageWebRequest () {
ZAutomationStorageWebRequest.super_.call(this);
this.allow_extensions = ['jpg', 'jpeg', 'png', 'gif', 'svg'];
this.res = {
status: 200,
headers: {
"Content-Type": "application/json; charset=utf-8"
},
body: null
}
};
inherits(ZAutomationStorageWebRequest, ZAutomationWebRequest);
ZAutomationStorageWebRequest.prototype.statusReport = function () {
return function () {
var reply = {
error: null,
data: "OK",
code: 200
};
this.initResponse(reply);
}
}
ZAutomationStorageWebRequest.prototype.uploadFileFunc = function () {
var self = this;
return function () {
var reply = {
error: 'Permission dendied',
data: null,
code: 403
};
if (req.role === controller.auth.ROLE.ADMIN) {
var file = self.req.body.file,
date = new Date(),
extension = file.name.split('.').pop().toLowerCase(),
fileName,
type;
reply = {
error: 'Allow extensions ' + self.allow_extensions.join(','),
data: null,
code: 400
};
if (extension === 'jpg') {
extension = 'jpeg';
}
fileName = 'storage-' + (+date / 1000).toFixed(0) + '.' + extension;
if (self.allow_extensions.indexOf(extension) !== -1) {
type = 'image/' + extension;
file.type = type;
file.createdAt = date.toJSON();
saveObject(fileName, file, true);
reply = {
error: null,
data: {
uri: '/ZAutomation/storage/' + fileName,
originalName: file.name,
length: file.length,
type: type
},
code: 200
};
}
}
self.initResponse(reply)
}
};
ZAutomationStorageWebRequest.prototype.getFileFunc = function (fileId) {
var self = this;
return function () {
var file = loadObject(fileId),
ifNoneMatch = self.req.headers.hasOwnProperty('If-None-Match');
if (file && !ifNoneMatch) {
self.res.headers = {
'Content-Type': file.type,
ETag: 'W/' + fileId + file.createdAt,
'Cache-Control': 'public, max-age=31536000',
'Last-Modified': (new Date(file.createdAt)).toUTCString()
};
self.res.body = file.content;
self.res.code = 200;
} else if (file && ifNoneMatch && self.req.headers['If-None-Match'] === 'W/' + fileId + file.createdAt) {
self.res = {
status: 304,
headers: {
"API-Version": "2.0.1",
'Content-Type': file.type
},
body: ''
};
} else {
self.initResponse({
data: null,
error: 'File isn\'t found',
code: 404
});
}
}
};
ZAutomationStorageWebRequest.prototype.dispatchRequest = function (method, url) {
// Default handler is NotFound
var self = this,
handlerFunc = this.NotFound;
// ---------- Test exact URIs ---------------------------------------------
if ("GET" === method && "/status" === url) {
handlerFunc = self.statusReport();
} else if ("POST" === method) {
handlerFunc = self.uploadFileFunc();
}
// ---------- Test regexp URIs --------------------------------------------
var re, reTest, fileId;
// --- Perform vDev command
if (handlerFunc === this.NotFound) {
re = /\/(.+)/;
reTest = re.exec(url);
if (!!reTest) {
fileId = reTest[1];
if ("GET" === method && !!fileId) {
handlerFunc = self.getFileFunc(fileId);
} else {
handlerFunc = self.uploadFileFunc();
}
}
}
// --- Proceed to checkout =)
return handlerFunc;
};
================================================
FILE: Utils.js
================================================
// Comon utilities and functions
var console = {
log: debugPrint,
warn: debugPrint,
error: debugPrint,
debug: debugPrint,
logJS: function () {
var arr = [], pretty = undefined;
for (var key in arguments) {
if (key == 0 && arguments[key] === "pretty") { // unstrict key == 0 since it is a string
pretty = " ";
continue;
}
arr.push(JSON.stringify(arguments[key], undefined, pretty));
}
debugPrint(arr);
},
logJSP: function() {
Array.prototype.unshift.call(arguments, "pretty");
console.logJS.apply(null, arguments);
}
};
function inherits(ctor, superCtor) {
Object.defineProperty(ctor, "super_", {
value: superCtor,
enumerable: false,
writable: false,
configurable: false
});
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
}
function in_array(array, value) {
return -1 !== array.indexOf(value);
}
function is_function(func) {
return !!(func && func.constructor && func.call && func.apply);
}
function has_key(obj, key) {
return -1 !== Object.keys(obj).indexOf(key);
}
function get_values(obj) {
var res = [];
Object.keys(obj).forEach(function (key) {
res.push(obj[key]);
});
return res;
}
function byteArrayToString(data) {
if (typeof ArrayBuffer !== 'undefined' && (data instanceof ArrayBuffer)) {
data = new Uint8Array(data);
}
var output = "";
for (var i = 0; i < data.byteLength; i++) {
output += String.fromCharCode(data[i]);
}
return output;
}
function byteArrayToHexString(data) {
var output = "";
for (var i = 0; i < data.byteLength; i++) {
output += ('0' + data[i].toString(16)).slice(-2);
}
return output;
}
function generateSalt() {
return Base64.encode(byteArrayToString(crypto.random(64)));
}
function hashPassword(password, salt) {
return Base64.encode(byteArrayToString(crypto.sha512(password + salt)));
}
function has_higher_version(newVersion, currVersion) {
var isHigher = false,
newVersion = newVersion && newVersion.toString() ? newVersion.toString().split('.') : null,
currVersion = currVersion && currVersion.toString() ? currVersion.toString().split('.') : null;
if (!!newVersion && !!currVersion) {
for (var i = 0; i < currVersion.length; i++) {
if ((parseInt(currVersion[i], 10) < parseInt(newVersion[i], 10)) || ((parseInt(currVersion[i], 10) <= parseInt(newVersion[i], 10)) && (!currVersion[i + 1] && newVersion[i + 1] && parseInt(newVersion[i + 1], 10) > 0))) {
isHigher = true;
break;
}
}
}
return isHigher;
}
/*
* Iterate trough object, find the key and change its value
* will change all keys that are equal to key
*/
function changeObjectValue(obj, key, value) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) {
continue;
}
// arrays and objects are treated as objects
if (!!obj[i] && typeof obj[i] === 'object') {
objects = objects.concat(changeObjectValue(obj[i], key));
} else if (i === key) {
obj[i] = value;
}
}
return obj;
}
var Base64 = {
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
encode: function (e) {
var t = "";
var n, r, i, s, o, u, a;
var f = 0;
e = Base64._utf8_encode(e);
while (f < e.length) {
n = e.charCodeAt(f++);
r = e.charCodeAt(f++);
i = e.charCodeAt(f++);
s = n >> 2;
o = (n & 3) << 4 | r >> 4;
u = (r & 15) << 2 | i >> 6;
a = i & 63;
if (isNaN(r)) {
u = a = 64
} else if (isNaN(i)) {
a = 64
}
t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a)
}
return t
},
decode: function (e) {
var t = "";
var n, r, i;
var s, o, u, a;
var f = 0;
e = e.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (f < e.length) {
s = this._keyStr.indexOf(e.charAt(f++));
o = this._keyStr.indexOf(e.charAt(f++));
u = this._keyStr.indexOf(e.charAt(f++));
a = this._keyStr.indexOf(e.charAt(f++));
n = s << 2 | o >> 4;
r = (o & 15) << 4 | u >> 2;
i = (u & 3) << 6 | a;
t = t + String.fromCharCode(n);
if (u != 64) {
t = t + String.fromCharCode(r)
}
if (a != 64) {
t = t + String.fromCharCode(i)
}
}
t = Base64._utf8_decode(t);
return t
},
_utf8_encode: function (e) {
var t = "";
for (var n = 0; n < e.length; n++) {
var r = e.charCodeAt(n);
if (r < 128) {
t += String.fromCharCode(r)
} else if (r > 127 && r < 2048) {
t += String.fromCharCode(r >> 6 | 192);
t += String.fromCharCode(r & 63 | 128)
} else {
t += String.fromCharCode(r >> 12 | 224);
t += String.fromCharCode(r >> 6 & 63 | 128);
t += String.fromCharCode(r & 63 | 128)
}
}
return t
},
_utf8_decode: function (e) {
var t = "";
var n = 0;
var r = c1 = c2 = 0;
while (n < e.length) {
r = e.charCodeAt(n);
if (r < 128) {
t += String.fromCharCode(r);
n++
} else if (r > 191 && r < 224) {
c2 = e.charCodeAt(n + 1);
t += String.fromCharCode((r & 31) << 6 | c2 & 63);
n += 2
} else {
c2 = e.charCodeAt(n + 1);
c3 = e.charCodeAt(n + 2);
t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
n += 3
}
}
return t
}
};
var formRequest = {
_randomString: function () {
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var rString = '';
for (var i = 0; i < 15; i++) {
var rnum = Math.floor(Math.random() * chars.length);
rString += chars.substring(rnum, rnum + 1);
}
return rString;
},
send: function (formElements, method, url) {
var boundary = "----WebKitFormBoundary" + formRequest._randomString();
var obj = {};
// set method
obj.method = method;
// set headers
obj.headers = {
"Content-Type": "multipart/form-data; boundary=" + boundary
};
// set url
obj.url = url;
// init data
obj.data = "";
// create form boundary
for (var index in formElements) {
obj.data += '--' + boundary + '\r\n';
obj.data += 'Content-Disposition: form-data; name="' + formElements[index].name + '"' + (formElements[index].filename ? ('; filename="' + formElements[index].filename) + '"' : '') + '\r\n';
obj.data += formElements[index].type ? ('Content-Type: ' + formElements[index].type + '\r\n\r\n') : '\r\n';
obj.data += formElements[index].value + '\r\n';
}
;
// end of boundary
obj.data += '\r\n--' + boundary + '--\r\n';
// return cloud server response
return http.request(obj);
}
};
function getHRDateformat(now) {
var ts = now.getFullYear() + "-";
ts += ("0" + (now.getMonth() + 1)).slice(-2) + "-";
ts += ("0" + now.getDate()).slice(-2) + "-";
ts += ("0" + now.getHours()).slice(-2) + "-";
ts += ("0" + now.getMinutes()).slice(-2);
return ts;
};
function checkBoxtype(type) {
var match = false;
try {
var bT = system('cat /etc/z-way/box_type');
bT.forEach(function (bType) {
match = typeof bType === 'string' && (bType.indexOf(type) > -1 || bType === type) ? true : false;
});
} catch (e) {
}
return match;
};
function parseToObject(object) {
return object && typeof object === "string" ? JSON.parse(object) : object;
};
function checkInternetConnection(host_url) {
var cn = false,
response = 'in progress',
d = Date.now() + 15000; // wait not more than 15 sec
// try to reach google to check for internet connection
http.request({
url: host_url,
async: true,
success: function (res) {
response = 'done';
cn = true;
},
error: function (res) {
response = 'failed';
}
});
// wait for response
while (Date.now() < d && response === 'in progress') {
processPendingCallbacks();
}
if (response === 'in progress') {
response = 'failed';
}
return cn;
};
/*
* check for true / false
* also if the variable is from type string e.g. 'true' / 'false'
*/
function retBoolean(boolean) {
if (boolean === true || boolean === 'true') {
return true;
} else {
return false;
}
};
/*
* find the smallest not assigned value (integer) of a specific key within array objects
*/
function findSmallestNotAssignedIntegerValue (array, key) {
var value = 1,
maxValue = null,
listValues = [];
listValues = array.map(function(entry) {
return Number.isInteger(entry[key]) ? entry[key] : parseInt(entry[key],10);
});
maxValue = Math.max.apply(null, listValues);
for (var i = 1; i <= maxValue; i++) {
if (listValues.indexOf(i) < 0) {
value = i;
break;
} else if (i == maxValue) {
value = i + 1;
}
}
return value;
};
/*
* transform the publicKey into usual dsk format: xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
*/
function transformPublicKeyToDSK (publicKey) {
var dsk = '';
if (_.isArray(publicKey) && publicKey.length > 0) {
dsk = publicKey.map(function(x, i, a) { if (i % 2 == 0) return x * 256 + a[i + 1]; }).filter(function(x) { return x != undefined; }).map(function(x) { return ("00000" + x).slice(-5); }).slice(0, 8).join('-');
}
return dsk;
}
/*
* Dump object and fix circular references to output it
* (for debug purposes)
*/
function dumpObject(obj, ancetors) {
if (typeof obj !== "object") return obj;
if (obj === null) return null;
if (obj === undefined) return undefined;
var result = Array.isArray(obj) ? [] : {} ;
var keys = Object.keys(obj);
if (!ancetors) ancetors = [];
for (var i in keys) {
var key = keys[i];
if (typeof obj[key] === "object") {
var circular = false;
for (var j in ancetors) {
if (obj[key] === ancetors[j]) {
circular = true;
break;
}
}
if (circular) {
result[key] = "circular reference to ancetor (" + (ancetors.length - j) + " up)";
} else {
var new_ancetors = ancetors.slice(); // copy array
new_ancetors.push(obj);
result[key] = dumpObject(obj[key], new_ancetors);
}
} else {
result[key] = obj[key];
}
}
return result;
}
function debugPrintStack() {
try {
throw new Error("Printing stack trace");
} catch(e) {
console.log(e.stack);
}
}
================================================
FILE: Webserver.js
================================================
/*** Initialize Webserver and Handlers *****************************************
Version:
-------------------------------------------------------------------------------
Author: Serguei Poltorak <ps@zwave.me>
Copyright: (c) ZWave.Me, 2015
******************************************************************************/
ws = new WebServer(8083, function(req) {
if (req.method === "OPTIONS") {
return this.addHTTPHeaders({
status: 200
});
}
var found = ws.find(req);
if (found) {
var auth = controller.auth.resolve(req, found.role);
if (!auth) {
return this.addHTTPHeaders({
status: 401,
body: "Not logged in"
});
} else if (controller.auth.isAuthorized(auth.role, found.role)) {
return this.addHTTPHeaders(ws.execute(found.name, req, auth));
} else {
return this.addHTTPHeaders({
status: 403,
body: 'Permission denied'
});
}
}
return null;
}, function(req) {
var auth = controller.auth.resolve(req, controller.auth.ROLE.USER);
if (!auth) {
return 0; // there is no profile with Id = 0
} else {
return auth.user;
}
}, function(user, msg) {
var obj = JSON.parse(msg);
var profile = controller.getProfile(user);
if (profile && obj.event === "httpEncapsulatedRequest") {
var role = profile.role;
// authentication data
var auth = { user: user, role: role, token: "....." };
// extract query string
var query = {};
var url = obj.data.url;
var i = url.indexOf("?");
if (i > -1) {
url.substring(i + 1).split("&").map(function(q) {
var qq = q.split("=");
query[qq[0]] = qq[1]
});
url = url.substring(0, i);
}
// body
var body = obj.data.body;
var responseEvent = obj.responseEvent;
var req = {
method: obj.data.method ? obj.data.method.toUpperCase() : "GET",
url: url,
fullUrl: obj.data.url,
query: query,
body: (typeof body === "string" || typeof body === "undefined") ? body : JSON.stringify(body),
peer: {
address: "....",
port: 0000
},
headers: {},
__authMethod: "....",
user: auth.user,
role: auth.role,
authToken: auth.token
};
var found = ws.find(req);
var response;
if (found && controller.auth.isAuthorized(role, found.role)) {
response = ws.execute(found.name, req, auth);
} else {
response = {
status: 404
};
}
return {
"ws-reply-type": responseEvent,
"ws-reply-data": response
};
}
}, {
document_root: "htdocs"
});
ws.find = function(req) {
var q = req.url.substring(1).replace(/\//g, '.');
if (!q) return null;
var found = null;
if (this.externalNames.some(function(ext) {
found = ext;
return (ext.name.length < q.length && q.slice(0, ext.name.length + 1) === ext.name + ".") || (ext.name === q);
})) {
return found;
} else {
return null;
}
};
ws.execute = function(name, req, auth) {
var cache = this.evalCache || (this.evalCache = {});
var handler = cache[name] || (cache[name] = evalPath(name));
return handler(req.url.substring(name.length + 1), req, auth);
};
ws.externalNames = []; // array of object {name, role}
ws.allowExternalAccess = function(name, role) {
// refresh cache anyways, even if adding duplicate name
if (this.evalCache)
delete this.evalCache[name];
var idx = this.externalNames.map(function (ext) { return ext.name}).indexOf(name);
if (idx >= 0) return;
this.externalNames.push({name: name, role: role || controller.auth.ROLE.ADMIN});
this.externalNames.sort(function(x, y) {
return (y.name.length - x.name.length) || (x.name > y.name ? 1 : -1);
});
};
ws.revokeExternalAccess = function(name) {
// remove cached handler (if any)
if (this.evalCache)
delete this.evalCache[name];
var idx = this.externalNames.map(function (ext) { return ext.name}).indexOf(name);
if (idx === -1) return;
this.externalNames.splice(idx, 1);
};
// Standard HTTP headers: HTTP and keep-laive
ws.allow_headers = [
'Authorization',
'Accept-Ranges',
'Content-Encoding',
'Content-Length',
'Content-Range',
'Content-Type',
'ETag',
'X-API-VERSION',
'Date',
'Cache-Control',
'If-None-Match',
'Content-Language',
'Accept-Language',
'X-ZBW-SESSID',
'ZWAYSession'
].join(', ');
ws.addHTTPHeaders = function (ret) {
if (!ret.headers) ret.headers = {};
ret.headers['Access-Control-Allow-Origin'] = '*';
ret.headers['Access-Control-Allow-Methods'] = 'GET, PUT, POST, DELETE, OPTIONS';
ret.headers['Access-Control-Allow-Headers'] = this.allow_headers;
ret.headers['Access-Control-Expose-Headers'] = this.allow_headers;
ret.headers['Connection'] = 'keep-alive';
ret.headers['Date'] = (new Date()).toUTCString();
return ret;
};
================================================
FILE: WebserverRequestRouter.js
================================================
/*** ZAutomationAPI Web Request Handler *****************************************
Version:
-------------------------------------------------------------------------------
Author: Stanislav Morozov <r3b@seoarmy.ru>
Copyright: (c) ZWave.Me, 2014
******************************************************************************/
// ----------------------------------------------------------------------------
// --- ZAutomationWebRequest
// ----------------------------------------------------------------------------
function ZAutomationWebRequest() {
this.req = {};
this.res = {
status: 501,
headers: {
"X-API-VERSION": "2.0.1",
"Content-Type": "text/plain; charset=utf-8"
},
body: null
};
this.error = null;
}
ZAutomationWebRequest.prototype.handlerFunc = function () {
var self = this;
return function () {
return self.handleRequest.apply(self, arguments);
};
};
ZAutomationWebRequest.prototype.initResponse = function (response) {
var that = this,
reply,
version = "2.0.1",
fields,
object = {},
data,
mainKey = null,
subPaths = ['notifications', 'devices'],
tempData,
pager = null,
limit = that.req.query.hasOwnProperty('limit') ? parseInt(that.req.query['limit']) : 10,
offset = that.req.query.hasOwnProperty('offset') ? parseInt(that.req.query['offset']) : 0,
pagination = that.req.query.hasOwnProperty('pagination') ? that.req.query['pagination'] : false,
query = that.req.query.hasOwnProperty('q') ? String(that.req.query['q']).toLowerCase() : null,
httpCode = {
200: "200 OK",
201: "201 Created",
204: "204 No Content",
304: "304 Not Modified",
400: "400 Bad Request",
401: "401 Unauthorized",
403: "403 Forbidden",
404: "404 Not Found",
405: "405 Method Not Allowed",
501: "501 Not Implemented",
500: "500 Internal server error"
};
response.data = response.data === undefined ? null : response.data;
response.error = response.error || null;
response.code = response.code || 200;
response.contentType = response.contentType || "application/json; charset=utf-8";
response.message = response.message || null;
tempData = response.data;
data = response.data;
if (data) {
subPaths.forEach(function (path) {
if (response.data.hasOwnProperty(path)) {
mainKey = path;
tempData = response.data[path];
data = response.data[path];
}
});
}
// filter fields
if (!!tempData && response.code === 200 && that.req.query.hasOwnProperty('fields')) {
fields = that.req.query['fields'].split(',');
if (fields.length) {
if (Array.isArray(tempData)) {
data = [];
tempData.forEach(function (model) {
object = {};
Object.keys(model).forEach(function (key) {
if (fields.indexOf(key) !== -1) {
object[key] = model[key];
}
});
data.push(object);
});
} else {
data = {};
Object.keys(response.data).forEach(function (key) {
if (fields.indexOf(key) !== -1) {
data[key] = response.data[key];
}
});
}
}
}
if (Array.isArray(tempData) && mainKey) {
// search
if (query && Array.isArray(tempData)) {
tempData = [];
if (mainKey === 'devices') {
data.forEach(function (obj) {
if (obj.metrics.title.toLowerCase().indexOf(query) !== -1) {
tempData.push(obj);
}
});
} else if (mainKey === 'notifications') {
data.forEach(function (obj) {
if (obj.message.toLowerCase().indexOf(query) !== -1) {
tempData.push(obj);
}
});
}
data = tempData;
}
// pager
if (limit > 0 && offset >= 0 && String(pagination) === 'true') {
data = data.slice(offset, offset + limit);
pager = {
total: data.length,
totalPage: Math.round(data.length / limit),
limit: limit,
offset: offset,
page: (offset + limit) / limit
};
}
}
// include
if (!!mainKey) {
response.data[mainKey] = data;
data = response.data;
}
if (that.req.query.hasOwnProperty('suppress_response_codes') && String(that.req.query.suppress_response_code) === 'true') {
response.code = '200';
} else {
if (!!data) {
response.code = response.code || 200;
} else if (that.req.method === 'DELETE' || !data) {
response.code = response.code || 204;
response.data = null;
response.message = '204 No Content';
}
}
if (String(pagination) === 'true') {
_.extend(data, {
pager: {
offset: offset,
limit: limit,
page_total: response.data[mainKey].length
}
});
}
reply = {
data: data,
code: response.code,
message: httpCode[response.code],
error: response.error
};
if (pager) {
reply.pager = pager;
}
var headers = {
'Content-Type': response.contentType,
'X-API-VERSION': version,
};
if (response.code === 401 && !response.suppress401Auth) {
_.extend(headers, {'WWW-Authenticate': 'Basic realm="Z-Way ZAutomation API"'});
}
if (response.headers) {
for (var hname in response.headers) {
headers[hname] = response.headers[hname];
}
}
that.res = {
status: response.code,
body: JSON.stringify(reply),
headers: headers
};
return that.res;
};
ZAutomationWebRequest.prototype.dispatchRequest = function (method, url) {
return this.NotImplementedReply;
};
ZAutomationWebRequest.prototype.handleRequest = function (url, request) {
var self = this,
requestProcessorFunc,
bodyLength,
response;
response = {
data: null,
error: null,
code: 200,
message: null
};
// Fill internal structures
this.req.url = url;
this.req.fullUrl = request.fullUrl || "";
this.req.method = request.method;
this.req.query = request.query || {};
this.req.body = request.body || request.data;
this.req.headers = request.headers || {};
this.req.peer = request.peer;
this.req.user = request.user;
this.req.role = request.role;
this.req.authToken = request.authToken;
var contentType = request.headers['Content-Type'] || "";
// set defaultLang
if (self.req.query.hasOwnProperty('lang') || self.req.headers['Accept-Language']) {
self.controller.setDefaultLang(self.req.query.lang || self.req.headers['Accept-Language']);
}
if (['PUT', 'POST'].indexOf(this.req.method) !== -1 && contentType.toLowerCase().indexOf('application/json') !== -1) {
try {
this.req.reqObj = JSON.parse(this.req.body);
} catch (ex) {
response.code = 500;
response.error = 'JSON Parse Error [Syntax Error]';
}
}
if (response.error === null) {
// Get and run request processor func
requestProcessorFunc = this.dispatchRequest(request.method, url);
response = requestProcessorFunc.call(this);
}
// Return to the z-way-http
return response ? this.initResponse(response) : this.res;
};
ZAutomationWebRequest.prototype.NotImplementedReply = function () {
this.res = {
status: 501,
body: "Not implemented, yet",
headers: {
"Content-Type": "text/plain; charset=utf-8"
}
};
};
ZAutomationWebRequest.prototype.NotFound = function () {
this.res = {
status: 404,
headers: {
"Content-Type": "text/plain; charset=utf-8"
},
body: "Not Found"
};
};
================================================
FILE: ZAutomationAPIProvider.js
================================================
/*** ZAutomationAPI Provider **************************************************
Version:
-------------------------------------------------------------------------------
Author: Gregory Sitnin <sitnin@z-wave.me>
Copyright: (c) ZWave.Me, 2013
******************************************************************************/
// ----------------------------------------------------------------------------
// --- ZAutomationAPIWebRequest
// ----------------------------------------------------------------------------
executeFile("router.js");
function ZAutomationAPIWebRequest(controller) {
ZAutomationAPIWebRequest.super_.call(this);
this.ROLE = controller.auth.ROLE;
this.router = new Router("/v1");
this.controller = controller;
this.res = {
status: 200,
headers: {
"Content-Type": "application/json; charset=utf-8"
},
body: null
};
this.registerRoutes();
};
var ZAutomationWebRequest = ZAutomationWebRequest || function() {};
inherits(ZAutomationAPIWebRequest, ZAutomationWebRequest);
_.extend(ZAutomationAPIWebRequest.prototype, {
registerRoutes: function() {
this.router.get("/status", this.ROLE.USER, this.statusReport);
this.router.get("/session", this.ROLE.ANONYMOUS, this.verifySession);
this.router.post("/login", this.ROLE.ANONYMOUS, this.verifyLogin);
this.router.get("/logout", this.ROLE.USER, this.doLogout);
this.router.get("/notifications", this.ROLE.USER, this.exposeNotifications);
this.router.put("/notifications", this.ROLE.ADMIN, this.redeemNotifications);
this.router.del("/notifications", this.ROLE.ADMIN, this.deleteNotifications);
this.router.get("/devices", this.ROLE.USER, this.listDevices);
this.router.get("/restart", this.ROLE.ADMIN, this.restartController);
this.router.get("/locations", this.ROLE.USER, this.listLocations);
this.router.get("/profiles", this.ROLE.USER, this.listProfiles);
this.router.get("/namespaces", this.ROLE.ADMIN, this.listNamespaces);
this.router.post("/profiles", this.ROLE.ADMIN, this.createProfile);
this.router.get("/locations/add", this.ROLE.ADMIN, this.addLocation);
this.router.post("/locations", this.ROLE.ADMIN, this.addLocation);
this.router.get("/locations/remove", this.ROLE.ADMIN, this.removeLocation);
this.router.get("/locations/update", this.ROLE.ADMIN, this.updateLocation);
this.router.get("/modules", this.ROLE.ADMIN, this.listModules);
this.router.get("/modules/categories", this.ROLE.ADMIN, this.listModulesCategories);
// module installation / update
this.router.post("/modules/install", this.ROLE.ADMIN, this.installModule);
this.router.post("/modules/update", this.ROLE.ADMIN, this.updateModule);
// module tokens
this.router.get("/modules/tokens", this.ROLE.ADMIN, this.getModuleTokens);
this.router.put("/modules/tokens", this.ROLE.ADMIN, this.storeModuleToken);
this.router.del("/modules/tokens", this.ROLE.ADMIN, this.deleteModuleToken);
this.router.get("/instances", this.ROLE.ADMIN, this.listInstances);
this.router.post("/instances", this.ROLE.ADMIN, this.createInstance);
this.router.post("/upload/file", this.ROLE.ADMIN, this.uploadFile);
// patterned routes, right now we are going to just send in the wrapper
// function. We will let the handler consumer handle the application of
// the parameters.
this.router.get("/devices/:v_dev_id/command/:command_id", this.ROLE.USER, this.performVDevCommandFunc);
this.router.get("/devices/:v_dev_id/referenced", this.ROLE.ADMIN, this.getDeviceReference);
this.router.get('/devices/:dev_id/:param/:innerParam', this.ROLE.USER, this.getVDevParam);
this.router.get('/devices/:dev_id/:param', this.ROLE.USER, this.getVDevParam);
this.router.get("/locations/:location_id/namespaces/:namespace_id", this.ROLE.ADMIN, this.getLocationNamespacesFunc);
this.router.get("/locations/:location_id/namespaces", this.ROLE.ADMIN, this.getLocationNamespacesFunc);
this.router.del("/locations/image/:location_id", this.ROLE.ADMIN, this.removeLocationImage, [parseInt]);
this.router.del("/locations/:location_id", this.ROLE.ADMIN, this.removeLocation, [parseInt]);
this.router.put("/locations/:location_id", this.ROLE.ADMIN, this.updateLocation, [parseInt]);
this.router.get("/locations/:location_id", this.ROLE.ADMIN, this.getLocationFunc);
this.router.get("/notifications/:notification_id", this.ROLE.USER, this.exposeNotifications, [parseInt]);
this.router.del("/notifications/:notification_id", this.ROLE.USER, this.deleteNotifications, [parseInt]);
this.router.put("/notifications/:notification_id", this.ROLE.USER, this.redeemNotifications, [parseInt]);
this.router.post("/profiles/qrcode/:profile_id", this.ROLE.USER, this.getQRCodeString, [parseInt]);
this.router.del("/profiles/:profile_id/token/:token", this.ROLE.USER, this.removeToken, [parseInt, undefined]);
this.router.put("/profiles/:profile_id/token/:token", this.ROLE.USER, this.permanentToken, [parseInt, undefined]);
this.router.get("/profiles/token/local/:profile_id", this.ROLE.USER, this.generateLocalAccessToken, [parseInt]);
this.router.del("/profiles/:profile_id", this.ROLE.ADMIN, this.removeProfile, [parseInt]);
this.router.put("/profiles/:profile_id", this.ROLE.USER, this.updateProfile, [parseInt]);
this.router.get("/profiles/:profile_id", this.ROLE.USER, this.listProfiles, [parseInt]);
this.router.del("/profile", this.ROLE.USER, this.removeOwnProfile);
this.router.post("/oauth2", this.ROLE.ADMIN, this.createOAuth2Profile);
this.router.get("/notificationFiltering", this.ROLE.USER, this.notificationFilteringGet);
this.router.put("/notificationFiltering", this.ROLE.USER, this.notificationFilteringSet);
this.router.get("/notificationChannels", this.ROLE.USER, this.notificationChannelsGet);
this.router.get("/notificationChannels/all", this.ROLE.ADMIN, this.notificationChannelsGetAll);
this.router.post("/auth/forgotten", this.ROLE.ANONYMOUS, this.restorePassword);
this.router.post("/auth/forgotten/:profile_id", this.ROLE.ANONYMOUS, this.restorePassword, [parseInt]);
this.router.put("/auth/update/:profile_id", this.ROLE.ANONYMOUS, this.updateProfileAuth, [parseInt]);
this.router.put("/devices/:dev_id", this.ROLE.USER, this.setVDevFunc);
this.router.get("/devices/:dev_id", this.ROLE.USER, this.getVDevFunc);
this.router.get("/instances/:instance_id", this.ROLE.ADMIN, this.getInstanceFunc);
this.router.put("/instances/:instance_id", this.ROLE.ADMIN, this.reconfigureInstanceFunc, [parseInt]);
this.router.del("/instances/:instance_id", this.ROLE.ADMIN, this.deleteInstanceFunc, [parseInt]);
this.router.post("/modules/reset/:module_id", this.ROLE.ADMIN, this.resetModule);
this.router.del("/modules/delete/:module_id", this.ROLE.ADMIN, this.deleteModule);
// reinitialize apps from /modules or /userModules directory
this.router.get("/modules/reinitialize/:module_id", this.ROLE.ADMIN, this.reinitializeModule);
this.router.get("/modules/categories/:category_id", this.ROLE.ADMIN, this.getModuleCategoryFunc);
this.router.get("/modules/transform/reverse", this.ROLE.ADMIN, this.revertTransformModuleFlag);
this.router.post("/modules/transform", this.ROLE.ADMIN, this.transformModule);
this.router.get("/modules/:module_id", this.ROLE.ADMIN, this.getModuleFunc);
this.router.get("/namespaces/:namespace_id", this.ROLE.ADMIN, this.getNamespaceFunc);
this.router.get("/load/modulemedia/:module_name/:file_name", this.ROLE.ANONYMOUS, this.loadModuleMedia);
this.router.get("/load/image/:img_name", this.ROLE.ANONYMOUS, this.loadImage);
this.router.get("/backup", this.ROLE.ADMIN, this.backup);
this.router.post("/restore", this.ROLE.ADMIN, this.restore);
this.router.get("/resetToFactoryDefault", this.ROLE.ADMIN, this.resetToFactoryDefault);
// skins tokens
this.router.get("/skins/tokens", this.ROLE.ADMIN, this.getSkinTokens);
this.router.put("/skins/tokens", this.ROLE.ADMIN, this.storeSkinToken);
this.router.del("/skins/tokens", this.ROLE.ADMIN, this.deleteSkinToken);
this.router.get("/skins", this.ROLE.ADMIN, this.getSkins);
this.router.post("/skins/install", this.ROLE.ADMIN, this.addOrUpdateSkin);
this.router.put("/skins/update/:skin_id", this.ROLE.ADMIN, this.addOrUpdateSkin);
this.router.get("/skins/setToDefault", this.ROLE.ADMIN, this.setDefaultSkin);
this.router.get("/skins/active", this.ROLE.ANONYMOUS, this.getActiveSkin);
this.router.get("/skins/:skin_id", this.ROLE.ADMIN, this.getSkin);
this.router.put("/skins/:skin_id", this.ROLE.ADMIN, this.activateOrDeactivateSkin);
this.router.del("/skins/:skin_id", this.ROLE.ADMIN, this.deleteSkin);
this.router.get("/icons", this.ROLE.ADMIN, this.getIcons);
this.router.del("/icons/:icon_id", this.ROLE.ADMIN, this.deleteIcons);
this.router.post("/icons/upload", this.ROLE.ADMIN, this.uploadIcon);
this.router.post("/icons/install", this.ROLE.ADMIN, this.addOrUpdateIcons);
this.router.get("/system/webif-access", this.ROLE.ADMIN, this.setWebifAccessTimout);
this.router.get("/system/reboot", this.ROLE.ADMIN, this.rebootBox);
this.router.get("/system/wifiCli/settings", this.ROLE.ADMIN, this.getWiFiCliSettings);
this.router.post("/system/wifiCli/settings", this.ROLE.ADMIN, this.setWiFiCliSettings);
this.router.get("/system/connectionType", this.ROLE.ADMIN, this.getConnectionType);
this.router.post("/system/timezone", this.ROLE.ADMIN, this.setTimezone);
this.router.get("/system/time/get", this.ROLE.ANONYMOUS, this.getTime);
this.router.get("system/time/ntp/:action", this.ROLE.ADMIN, this.configNtp);
this.router.get("/system/remote-id", this.ROLE.ANONYMOUS, this.getRemoteId);
this.router.get("/system/ip-address", this.ROLE.ANONYMOUS, this.getIPAddress);
this.router.get("/system/first-access", this.ROLE.ANONYMOUS, this.getFirstLoginInfo);
this.router.get("/system/info", this.ROLE.ANONYMOUS, this.getSystemInfo);
this.router.post("/system/wifi/settings", this.ROLE.ADMIN, this.setWifiSettings);
this.router.get("/system/wifi/settings", this.ROLE.ADMIN, this.getWifiSettings);
this.router.get("/system/zwave/deviceInfoGet", this.ROLE.ADMIN, this.zwaveDeviceInfoGet);
this.router.get("/system/zwave/deviceInfoUpdate", this.ROLE.ADMIN, this.zwaveDeviceInfoUpdate);
this.router.get("/system/zwave/vendorsInfoGet", this.ROLE.ADMIN, this.zwaveVendorsInfoGet);
this.router.get("/system/zwave/vendorsInfoUpdate", this.ROLE.ADMIN, this.zwaveVendorsInfoUpdate);
this.router.put("/devices/reorder", this.ROLE.ADMIN, this.reorderDevices);
this.router.get("/redirect", this.ROLE.ANONYMOUS, this.redirectURL);
this.router.post("/redirect", this.ROLE.ANONYMOUS, this.redirectURL);
this.router.get("/demultiplex/:paths", this.ROLE.ANONYMOUS, this.demultiplex);
this.router.get('/expert/deviceDescription/:deviceId', this.ROLE.ADMIN, this.getDeviceDescription, [parseInt]);
this.router.get('/encryptionKeys', this.ROLE.ADMIN, this.encryptionKeys)
},
// Used by the android app to request server status
statusReport: function() {
var currentDateTime = new Date(),
reply = {
error: null,
data: 'OK',
code: 200
};
if (Boolean(this.error)) {
reply.error = "Internal server error. Please fill in bug report with request_id='" + this.error + "'";
reply.data = null;
reply.code = 503;
reply.message = "Service Unavailable";
}
return reply;
},
setLogin: function(profile, req) {
var sid, resProfile = {};
sid = this.controller.auth.checkIn(profile, req);
resProfile = this.controller.safeProfile(profile, ["authTokens"]);
resProfile.sid = sid;
if (profile.password !== 'admin' && !this.controller.config.hasOwnProperty('firstaccess') || this.controller.config.firstaccess === true) {
this.controller.config.firstaccess = false;
}
// if showWelcome flag is set in controller add showWelcome flag to profile and remove it from controller
if (!this.controller.config.firstaccess && this.controller.config.showWelcome) {
resProfile.showWelcome = true;
delete this.controller.config.showWelcome;
this.controller.saveConfig(true);
}
return {
error: null,
data: resProfile,
code: 200,
headers: {
"ZWAYSession": resProfile.sid,
"Set-Cookie": "ZWAYSession=" + sid + "; Path=/" // set cookie - it will duplicate header just in case client prefers cookies
}
};
},
// Method to return a 401 to the user
denyLogin: function(error) {
return {
error: error,
data: null,
code: 401,
suppress401Auth: true, // to suppress basic auth form from the browser
headers: {
"Set-Cookie": "ZWAYSession=deleted; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT" // clean cookie
}
}
},
// Returns user session information for the smarthome UI
verifySession: function() {
var auth = controller.auth.resolve(this.req, controller.auth.ROLE.USER);
if (!auth) {
return this.denyLogin("No valid user session found");
}
var profile = _.find(this.controller.profiles, function(profile) {
return profile.id === auth.user;
});
res = _.extend(this.controller.safeProfile(profile, ["authTokens"]), {sid: controller.auth.getSessionId(this.req)});
return {
error: null,
data: res,
code: 200,
headers: {
"ZWAYSession": res.sid,
"Set-Cookie": "ZWAYSession=" + res.sid + "; Path=/" // set cookie - it will duplicate header just in case client prefers cookies
}
};
},
// Check if login exists and password is correct
verifyLogin: function() {
var reqObj;
try {
reqObj = parseToObject(this.req.body);
} catch (ex) {
return {
error: ex.message,
data: null,
code: 500,
headers: null
};
}
var profile = _.find(this.controller.profiles, function(profile) {
return profile.login === reqObj.login;
});
if (profile) {
// check if the pwd matches
var pwd_check = reqObj.password ? (!profile.salt && profile.password === reqObj.password) || (profile.salt && profile.password === hashPassword(reqObj.password, profile.salt)) : false;
if (pwd_check) {
return this.setLogin(profile, this.req);
} else {
return this.denyLogin();
}
} else {
return this.denyLogin();
}
},
doLogout: function() {
var reply = {
error: null,
data: null,
code: 400,
headers: null
},
self = this,
session;
reply.headers = {
"Set-Cookie": "ZWAYSession=deleted; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT" // clean cookie
};
reply.code = 200;
var sessionId = this.controller.auth.getSessionId(this.req);
if (sessionId) {
var session = {};
var sessionProfile = _.find(this.controller.profiles, function(profile) {
var sess = _.find(profile.authTokens, function(authToken) {
return authToken.sid == sessionId;
});
if (sess) session = sess;
return sess;
});
if (session.expire !== 0) {
// do not logout from permanent tokens - they should be deleted explicitelly via remoteToken API call
this.controller.removeToken(sessionProfile, session.sid);
}
}
return reply;
},
// Devices
listDevices: function() {
var nowTS = Math.floor(Date.now() / 1000),
reply = {
error: null,
data: {
structureChanged: false,
updateTime: nowTS,
devices: []
}
},
since = this.req.query.hasOwnProperty("since") ? parseInt(this.req.query.since, 10) : 0;
reply.data.structureChanged = this.controller.lastStructureChangeTime >= since && since? true : false;
reply.data.devices = this.controller.devicesByUser(this.req.user, function(dev) {
return dev.get("updateTime") >= (reply.data.structureChanged ? 0 : since);
});
if (Boolean(this.req.query.pagination)) {
reply.data.total_count = devices.length;
}
return reply;
},
getVDevFunc: function(vDevId) {
var reply = {
error: null,
data: null
},
device = _.find(this.controller.devicesByUser(this.req.user), function(device) {
return device.id === vDevId;
});
if (device) {
reply.code = 200;
reply.data = device.toJSON();
} else {
reply.code = 404;
reply.error = "Device " + vDevId + " doesn't exist";
}
return reply;
},
getVDevParam: function (vDevId, param, innerParam) {
var reply = {
error: null,
data: null
},
device = _.find(this.controller.devicesByUser(this.req.user), function(device) {
return device.id === vDevId;
});
if (device) {
device = device.toJSON();
if (device.hasOwnProperty(param)) {
var field = device[param];
if (innerParam) {
if (field.hasOwnProperty(innerParam)) {
reply.code = 200;
reply.data = field[innerParam];
} else {
reply.code = 404;
reply.error = 'Parameter ' + param + '.' + innerParam +' in device ' + vDevId + ' doesn\'t exist';
}
} else {
reply.code = 200;
reply.data = field;
}
} else {
reply.code = 404;
reply.error = 'Parameter ' + param + ' in device ' + vDevId + ' doesn\'t exist';
}
} else {
reply.code = 404;
reply.error = "Device " + vDevId + " doesn't exist";
}
return reply;
},
setVDevFunc: function(vDevId) {
var reqObj,
device = null,
reply = {
error: null,
data: null,
code: 500,
},
result = false;
try {
reqObj = typeof this.req.body === 'string' ? JSON.parse(this.req.body) : this.req.body;
} catch (ex) {
reply.error = ex.message;
return reply;
}
// check security hole here!!!!
if (this.req.query.hasOwnProperty('icon')) {
device = this.controller.devices.get(vDevId);
if (device) {
device.set('customIcons', reqObj.customicons, {
silent: true
});
reply.data = "OK";
result = true;
}
} else {
device = this.controller.deviceByUser(vDevId, this.req.user);
if (device) {
reply.data = device.set(reqObj);
result = true;
}
}
if (result) {
reply.code = 200;
} else {
reply.code = 404;
reply.error = "Device " + vDevId + " doesn't exist";
}
return reply;
},
performVDevCommandFunc: function(vDevId, commandId) {
var reply = {
error: null,
data: null,
code: 200
},
result_execution_command,
vDev = this.controller.deviceByUser(vDevId, this.req.user);
if (vDev) {
result_execution_command = vDev.performCommand.call(vDev, commandId, this.req.query);
reply.data = !!result_execution_command ? result_execution_command : null;
} else {
reply.data = null;
reply.code = 404;
reply.error = "Device " + vDevId + " doesn't exist";
}
return reply;
},
getDeviceReference: function(vDevId) {
var reply = {
error: null,
data: this.controller.findModulesReferencingDeviceId(vDevId),
code: 200
};
return reply;
},
// Notifications
exposeNotifications: function(notificationId) {
var notifications,
reply = {
error: null,
data: null,
code: 200
},
timestamp = Date.now(),
since = this.req.query.hasOwnProperty("since") ? parseInt(this.req.query.since, 10) : 0,
to = (this.req.query.hasOwnProperty("to") ? parseInt(this.req.query.to, 10) : 0) || timestamp,
profile = this.controller.profileByUser(this.req.user),
devices = this.controller.devicesByUser(this.req.user).map(function(device) {
return device.id;
}),
test = function(n) {
return ((profile.hide_system_events === false && n.level !== 'device-info') || // hide_system_events = false
(profile.hide_all_device_events === false && n.level === 'device-info')) && // hide_device_events = false
(!profile.hide_single_device_events || profile.hide_single_device_events.indexOf(n.source) === -1) && // remove events from devices to hide
((n.level !== 'device-info' && devices.indexOf(n.source) === -1) || (n.level === 'device-info' && devices.indexOf(n.source) > -1)); // filter device by user
};
if (notificationId) {
notification = this.controller.notifications.get().filter(function(notification) {
return notification.id === notificationId && // filter by id
test(notification); // check against 2nd filter
});
if (notification.length > 0) {
reply.data = notification[0];
} else {
reply.code = 404;
reply.error = 'Not found';
}
} else {
notifications = this.controller.notifications.get().filter(function(notification) {
return notification.id >= since && notification.id <= to && // filter by time
test(notification); // check against 2nd filter
});
reply.data = {
updateTime: Math.floor(timestamp / 1000),
notifications: notifications
};
}
if (Boolean(this.req.query.pagination)) {
reply.data.total_count = notifications.length;
// !!! fix pagination
notifications = notifications.slice();
}
return reply;
},
// delete single notifications or all privious by a choosen timestamp
deleteNotifications: function(notificationId) {
var id = notificationId ? parseInt(notificationId) : 0,
reply = {
code: 500,
data: null,
error: "Something went wrong."
},
before;
before = this.req.query.hasOwnProperty("allPrevious") ? Boolean(this.req.query.allPrevious) : false;
redeemed = this.req.query.hasOwnProperty("allRedeemed") ? Boolean(this.req.query.allRedeemed) : false;
if (!redeemed) {
this.controller.deleteNotifications(id, before, function(notice) {
if (notice) {
reply.code = 204;
reply.data = null;
reply.error = null;
} else {
reply.code = 404;
reply.data = null;
reply.error = "Notifications not found.";
}
});
} else {
this.controller.deleteAllRedeemedNotifications(function(notice) {
if (notice) {
reply.code = 204;
reply.data = null;
reply.error = null;
}
});
}
return reply;
},
// redeem single or all notifications (true/false)
redeemNotifications: function(notificationId) {
var id = notificationId ? parseInt(notificationId) : 0,
reply = {
code: 500,
data: null,
error: "Something went wrong."
};
redeemed = this.req.body.hasOwnProperty("set_redeemed") ? retBoolean(this.req.body.set_redeemed) : false;
all = this.req.body.hasOwnProperty("all") ? retBoolean(this.req.body.all) : false;
if (!all) {
this.controller.redeemNotification(id, redeemed, function(notice) {
if (notice) {
reply.code = 204;
reply.data = null;
reply.error = null;
} else {
reply.code = 404;
reply.data = null;
reply.error = 'Notification not found.';
}
});
} else {
this.controller.redeemAllNotifications(redeemed, function(notice) {
if (notice) {
reply.code = 204;
reply.data = null;
reply.error = null;
}
});
}
return reply;
},
//locations
listLocations: function() {
var reply = {
data: null,
error: null
},
locations = this.controller.locationsByUser(this.req.user),
expLocations = [];
// generate namespaces per location
reply.code = 200;
reply.data = locations;
return reply;
},
// get location
getLocationFunc: function(locationId) {
var reply = {
data: null,
error: null
},
locations = this.controller.locationsByUser(this.req.user),
_location = [],
locationId = !isNaN(locationId) ? parseInt(locationId, 10) : locationId;
_location = this.controller.getLocation(locations, locationId);
// generate namespaces for location
if (_location) {
reply.data = _location;
reply.code = 200;
} else {
reply.code = 404;
reply.error = "Location " + locationId + " not found";
}
return reply;
},
//filter location namespaces
getLocationNamespacesFunc: function(locationId, namespaceId) {
var reply = {
data: null,
error: null
},
locations = this.controller.locationsByUser(this.req.user),
_location = [],
locationId = !isNaN(locationId) ? parseInt(locationId, 10) : locationId;
_location = this.controller.getLocation(locations, locationId);
// generate namespaces for location and get its namespaces
if (_location) {
// get namespaces by path (namespaceId)
if (!namespaceId) {
getFilteredNspc = _location.namespaces;
} else {
getFilteredNspc = this.controller.getListNamespaces(namespaceId, _location.namespaces);
}
if (!getFilteredNspc || (_.isArray(getFilteredNspc) && getFilteredNspc.length < 1)) {
reply.code = 404;
reply.error = "Couldn't find namespaces entry with: '" + namespaceId + "'";
} else {
reply.data = getFilteredNspc;
reply.code = 200;
}
} else {
reply.code = 404;
reply.error = "Location " + locationId === 0 ? 'globalRoom' : locationId + " not found";
}
return reply;
},
addLocation: function() {
var title,
reply = {
error: null,
data: null
},
reqObj,
locProps = {};
if (this.req.method === 'GET') {
reqObj = this.req.query;
} else if (this.req.method === 'POST') { // POST
try {
reqObj = JSON.parse(this.req.body);
} catch (ex) {
reply.code = 500;
reply.error = "Cannot parse POST request. ERROR:" + ex.message;
}
}
for (var property in reqObj) {
if (property !== 'id') {
locProps[property] = reqObj[property] ? reqObj[property] : null;
}
}
if (!!locProps.title) {
this.controller.addLocation(locProps, function(data) {
if (data) {
reply.code = 201;
reply.data = data;
} else {
reply.code = 500;
reply.error = "Location doesn't created: Parsing the arguments has failed.";
}
});
} else {
reply.code = 500;
reply.error = "Argument 'title' is required.";
}
return reply;
},
removeLocation: function(locationId) {
var id,
reqObj,
reply = {
error: null,
data: null,
code: 200
};
if (this.req.method === 'GET') {
id = parseInt(this.req.query.id);
} else if (this.req.method === 'DELETE' && locationId === undefined) {
try {
reqObj = JSON.parse(this.req.body);
} catch (ex) {
reply.error = ex.message;
}
id = reqObj.id;
} else if (this.req.method === 'DELETE' && locationId !== undefined) {
id = locationId;
}
if (!!id) {
if (id !== 0) {
this.controller.removeLocation(id, function(result) {
if (result) {
reply.code = 204;
reply.data = null;
} else {
reply.code = 404;
reply.error = "Location " + id + " doesn't exist";
}
});
} else {
reply.code = 403;
reply.error = "Permission denied";
}
} else {
reply.code = 400;
reply.error = "Argument id is required";
}
return reply;
},
removeLocationImage: function(locationId) {
var id,
user_img,
reqObj,
reply = {
error: null,
data: null,
code: 200
};
if (this.req.method === 'DELETE' && locationId === undefined) {
try {
reqObj = JSON.parse(this.req.body);
} catch (ex) {
reply.error = ex.message;
}
id = reqObj.id;
user_img = reqObj.user_img;
} else if (this.req.method === 'DELETE' && locationId !== undefined) {
id = locationId;
user_img = this.req.query.user_img;
}
if (!!id || user_img !== "") {
if (id !== 0) {
var location = this.controller.getLocation(this.controller.locations, id);
if (location) {
// check custom image exists
if (!loadObject(user_img)) {
reply.code = 404;
reply.error = "Location image " + user_img + " doesn't exist or already deleted.";
} else {
// delete custom room image
saveObject(user_img, null, true);
if (location.user_img == user_img && location.img_type == 'user') {
location.user_img = '';
location.img_type = '';
location.show_background = false;
} else if (location.user_img == user_img) {
location.user_img = '';
}
// update affected location
this.controller.updateLocation(location.id, location.title, location.user_img, location.default_img, location.img_type, location.show_background, location.main_sensors, function(data) {
if (data) {
reply.data = data;
} else {
reply.code = 404;
reply.error = "Location " + id + " doesn't exist.";
}
});
}
} else {
reply.code = 404;
reply.error = "Location " + id + " doesn't exist.";
}
} else {
reply.code = 403;
reply.error = "Permission denied.";
}
} else {
reply.code = 400;
reply.error = "Argument id, user_img is required.";
}
return reply;
},
updateLocation: function(locationId) {
var id,
title,
user_img,
default_img,
img_type,
show_background,
main_sensors,
reply = {
error: null,
data: null,
code: 200
},
reqObj;
if (locationId !== 0) {
if (this.req.method === 'GET') {
id = parseInt(this.req.query.id);
title = this.req.query.title;
} else if (this.req.method === 'PUT') {
try {
reqObj = JSON.parse(this.req.body);
} catch (ex) {
reply.error = ex.message;
}
id = locationId || reqObj.id;
title = reqObj.title;
user_img = reqObj.user_img || '';
default_img = reqObj.default_img || '';
img_type = reqObj.img_type || '';
show_background = reqObj.show_background || false;
main_sensors = reqObj.main_sensors || [];
}
if (!!title && title.length > 0) {
this.controller.updateLocation(id, title, user_img, default_img, img_type, show_background, main_sensors, function(data) {
if (data) {
reply.data = data;
} else {
reply.code = 404;
reply.error = "Location " + id + " doesn't exist";
}
});
} else {
reply.code = 400;
reply.error = "Arguments id & title are required";
}
} else {
reply.code = 403;
reply.error = "Permission denied.";
}
return reply;
},
// modules
listModules: function() {
var reply = {
error: null,
data: [],
code: 200
},
module = null;
Object.keys(this.controller.modules).sort().forEach(function(className) {
module = this.controller.getModuleData(className);
module.className = className;
if (module.location === ('userModules/' + className) && fs.list('modules/' + className)) {
module.hasReset = true;
} else {
module.hasReset = false;
}
if (module.singleton && _.any(this.controller.instances, function(instance) {
return instance.moduleId === module.id;
})) {
module.created = true;
} else {
module.created = false;
}
reply.data.push(module);
});
return reply;
},
getModuleFunc: function(moduleId) {
var reply = {
error: null,
data: null,
code: null
},
moduleData;
if (!this.controller.modules.hasOwnProperty(moduleId)) {
reply.code = 404;
reply.error = 'Instance ' + moduleId + ' not found';
} else {
// get module data
moduleData = this.controller.getModuleData(moduleId);
if (moduleData.location === ('userModules/' + moduleId) && fs.list('modules/' + moduleId)) {
moduleData.hasReset = true;
} else {
moduleData.hasReset = false;
}
reply.code = 200;
// replace namspace filters
reply.data = this.controller.replaceNamespaceFilters(moduleData);
}
return reply;
},
// modules categories
listModulesCategories: function() {
var reply = {
error: null,
data: null,
code: 200
};
reply.data = this.controller.getListModulesCategories();
return reply;
},
getModuleCategoryFunc: function(categoryId) {
var reply = {
error: null,
data: null,
code: 500
};
category = this.controller.getListModulesCategories(categoryId);
if (!Boolean(category)) {
reply.code = 404;
reply.error = "Categories " + categoryId + " not found";
} else {
reply.code = 200;
reply.data = category;
}
return reply;
},
transformModule: function() {
var reply = {
error: 'Something went wrong.',
data: null,
code: 500
},
reqObj = parseToObject(this.req.body),
sources = ['IfThen', 'LogicalRules', 'ScheduledScene', 'LightScene'],
targets = ['Rules', 'Schedules', 'Scenes'],
source = reqObj.source && ['IfThen', 'LogicalRules', 'ScheduledScene', 'LightScene'].indexOf(reqObj.source) > -1 ? reqObj.source : null,
target = reqObj.target && ['Rules', 'Schedules', 'Scenes'].indexOf(reqObj.target) > -1 ? reqObj.target : null,
pairing = false,
resultList = [];
try {
pairing = (target === 'Rules' && (source === 'IfThen' || source === 'LogicalRules')) ||
(target === 'Schedules' && source === 'ScheduledScene') ||
(target === 'Scenes' && source === 'LightScene');
if (pairing) {
resultList = this.controller.transformIntoNewInstance(source);
reply.code = 200;
reply.data = resultList;
reply.error = null;
} else {
reply.code = 400;
reply.error = 'Bad Request. Following transformations are allowed: IfThen/LogicalRules > Rules, ScheduledScene > Schedules, LightScene > Scenes';
}
} catch (e) {
reply.error += ' Error: ' + e.toString();
}
return reply;
},
revertTransformModuleFlag: function() {
var self = this,
reply = {
error: 'Something went wrong.',
data: null,
code: 500
},
transformationsDone = false;
try {
_.forEach(this.controller.instances, function(instance) {
if (instance.params.moduleAPITransformed) {
// remove transformed flag
delete instance.params.moduleAPITransformed;
self.controller.reconfigureInstance(instance.id, instance);
transformationsDone = true;
}
});
reply.code = 200;
reply.data = transformationsDone ? 'successfull' : 'No transformations found.';
reply.error = null;
} catch (e) {
reply.error += ' Error: ' + e.toString();
}
return reply;
},
// install module
installModule: function() {
var reply = {
error: {
key: null,
errorMsg: null
},
data: {
key: null,
appendix: null
},
code: 500
},
moduleUrl = parseToObject(this.req.body).moduleUrl,
result = "",
moduleId = moduleUrl.split(/[\/]+/).pop().split(/[.]+/).shift();
if (!this.controller.modules[moduleId]) {
// download and install the module
result = this.controller.installModule(moduleUrl, moduleId);
if (result === "done") {
loadSuccessfully = this.controller.loadInstalledModule(moduleId, 'userModules/', false);
if (loadSuccessfully) {
reply.code = 201;
reply.data.key = "app_installation_successful"; // send language key as response
} else {
reply.code = 201;
reply.data.key = "app_installation_successful_but_restart_necessary"; // send language key as response
}
} else {
reply.code = 500;
reply.error.key = 'app_failed_to_install';
}
} else {
reply.code = 409;
reply.error.key = 'app_from_url_already_exist';
}
return reply;
},
updateModule: function() {
var reply = {
error: {
key: null,
errorMsg: null
},
data: {
key: null,
appendix: null
},
code: 500
},
moduleUrl = parseToObject(this.req.body).moduleUrl,
result = "",
moduleId = moduleUrl.split(/[\/]+/).pop().split(/[.]+/).shift();
if (this.controller.modules[moduleId]) {
// download and install/overwrite the module
result = this.controller.installModule(moduleUrl, moduleId);
if (result === "done") {
loadSuccessfully = this.controller.reinitializeModule(moduleId, 'userModules/');
if (loadSuccessfully) {
reply.code = 200;
reply.data.key = "app_update_successful"; // send language key as response
} else {
reply.code = 200;
reply.data.key = "app_update_successful_but_restart_necessary"; // send language key as response
}
} else {
reply.code = 500;
reply.error.key = 'app_failed_to_update';
}
} else {
reply.code = 404;
reply.error.key = 'app_from_url_not_exist';
}
return reply;
},
deleteModule: function(moduleId) {
var reply = {
error: {
key: null
},
data: {
key: null,
appendix: null
},
code: 500
},
uninstall = false;
if (this.controller.modules[moduleId]) {
uninstall = this.controller.uninstallModule(moduleId);
if (uninstall) {
reply.code = 200;
reply.data.key = "app_delete_successful"; // send language key as response
} else {
reply.code = 500;
reply.error.key = 'app_failed_to_delete';
}
} else {
reply.code = 404;
reply.error.key = 'app_not_exist';
}
return reply;
},
resetModule: function(moduleId) {
var reply = {
error: {},
data: {},
code: 500
},
unload;
var result = "in progress";
if (this.controller.modules[moduleId]) {
if (this.controller.modules[moduleId].location === ('userModules/' + moduleId) && fs.list('modules/' + moduleId)) {
uninstall = this.controller.uninstallModule(moduleId, true);
if (uninstall) {
reply.code = 200;
reply.data.key = 'app_reset_successful_to_version';
reply.data.appendix = this.controller.modules[moduleId].meta.version;
} else {
reply.code = 500;
reply.error = 'There was an error during resetting the app ' + moduleId + '. Maybe a server restart could solve this problem.';
}
} else {
reply.code = 412;
reply.error.key = 'app_is_still_reseted';
}
} else {
reply.code = 404;
reply.error.key = 'app_not_exist';
}
return reply;
},
getModuleTokens: function() {
var reply = {
error: null,
data: null,
code: 500
},
tokenObj = {
tokens: []
},
getTokens = function() {
return loadObject('moduleTokens.json');
};
if (getTokens() === null) {
saveObject('moduleTokens.json', tokenObj, true);
}
if (!!getTokens()) {
reply.data = getTokens();
reply.code = 200;
} else {
reply.error = 'failed_to_load_tokens';
}
return reply;
},
storeModuleToken: function() {
var reply = {
error: null,
data: null,
code: 500
},
reqObj = parseToObject(this.req.body),
tokenObj = loadObject('moduleTokens.json');
if (tokenObj === null) {
saveObject('moduleTokens.json', tokenObj, true);
// try to load it again
tokenObj = loadObject('moduleTokens.json');
}
if (reqObj && reqObj.token && !!tokenObj && tokenObj.tokens) {
if (tokenObj.tokens.indexOf(reqObj.token) < 0) {
// add new token id
tokenObj.tokens.push(reqObj.token);
// save tokens
saveObject('moduleTokens.json', tokenObj, true);
reply.data = tokenObj;
reply.code = 201;
} else {
reply.code = 409;
reply.error = 'token_not_unique';
}
} else {
reply.error = 'failed_to_load_tokens';
}
return reply;
},
deleteModuleToken: function() {
var reply = {
error: null,
data: null,
code: 500
},
reqObj = parseToObject(this.req.body),
tokenObj = loadObject('moduleTokens.json');
if (reqObj && reqObj.token && !!tokenObj && tokenObj.tokens) {
if (tokenObj.tokens.indexOf(reqObj.token) > -1) {
// add new token id
tokenObj.tokens = _.filter(tokenObj.tokens, function(token) {
return token !== reqObj.token;
});
// save tokens
saveObject('moduleTokens.json', tokenObj, true);
reply.data = tokenObj;
reply.code = 200;
} else {
reply.code = 404;
reply.error = 'not_existing_token';
}
} else {
reply.error = 'failed_to_load_tokens';
}
return reply;
},
// reinitialize modules
reinitializeModule: function(moduleId) {
var reply = {
error: null,
data: null,
code: 500
},
location = [],
loadSuccessfully = 0;
if (fs.list('modules/' + moduleId)) {
location.push('modules/');
}
if (fs.list('userModules/' + moduleId)) {
location.push('userModules/');
}
if (location.length > 0) {
try {
_.forEach(location, function(loc) {
loadSuccessfully += this.controller.reinitializeModule(moduleId, loc);
});
if (loadSuccessfully > 0) {
reply.data = 'Reinitialization of app "' + moduleId + '" successfull.';
reply.code = 200;
}
} catch (e) {
reply.error = e.toString();
}
} else {
reply.code = 404;
reply.error = "App not found.";
}
return reply;
},
// instances
listInstances: function() {
var reply = {
error: null,
data: null,
code: 200
},
instances = this.controller.listInstances();
if (instances) {
reply.data = instances;
} else {
reply.code = 500;
reply.error = 'Could not list Instances.';
}
return reply;
},
createInstance: function() {
var reply = {
error: null,
data: null,
code: 500
},
reqObj = this.req.reqObj,
instance;
if (this.controller.modules.hasOwnProperty(reqObj.moduleId)) {
instance = this.controller.createInstance(reqObj);
if (!!instance && instance) {
reply.code = 201;
reply.data = instance;
} else {
reply.code = 500;
reply.error = "Cannot instantiate module " + reqObj.moduleId;
}
} else {
reply.code = 404;
reply.error = "Module " + reqObj.moduleId + " doesn't exist";
}
return reply;
},
getInstanceFunc: function(instanceId) {
var reply = {
error: null,
data: null,
code: 500
};
if (isNaN(instanceId)) {
instance = _.filter(this.controller.instances, function(i) {
return instanceId === i.moduleId;
});
} else {
instance = _.find(this.controller.instances, function(i) {
return parseInt(instanceId) === i.id;
});
}
if (!Boolean(instance) || instance.length === 0) {
reply.code = 404;
reply.error = "Instance " + instanceId + " is not found";
} else {
reply.code = 200;
reply.data = instance;
}
return reply;
},
reconfigureInstanceFunc: function(instanceId) {
var reply = {
error: null,
data: null
},
reqObj = this.req.reqObj,
instance;
if (!_.any(this.controller.instances, function(instance) {
return instanceId === instance.id;
})) {
reply.code = 404;
reply.error = "Instance " + instanceId + " doesn't exist";
} else {
instance = this.controller.reconfigureInstance(instanceId, reqObj);
if (instance) {
reply.code = 200;
reply.data = instance;
} else {
reply.code = 500;
reply.error = "Cannot reconfigure module " + instanceId + " config";
}
}
return reply;
},
deleteInstanceFunc: function(instanceId) {
var reply = {
error: null,
data: null,
code: 200
};
if (!_.any(this.controller.instances, function(instance) {
return instance.id === instanceId;
})) {
reply.code = 404;
reply.error = "Instance " + instanceId + " not found";
} else {
reply.code = 204;
reply.data = null;
this.controller.deleteInstance(instanceId);
}
return reply;
},
// profiles
listProfiles: function(profileId) {
var reply = {
error: null,
data: null,
code: 500
},
profiles,
getProfile,
excl = [];
// list all profiles only if user has 'admin' permissions
if (!_.isNumber(profileId)) {
if (this.req.role === this.ROLE.ADMIN) {
profiles = this.controller.getListProfiles();
} else {
getProfile = this.controller.safeProfile(this.controller.getProfile(this.req.user), ["role", "authTokens"]);
if (getProfile) {
profiles = [getProfile];
}
}
if (!Array.isArray(profiles)) {
reply.code = 500;
reply.error = "Unknown error";
} else {
reply.code = 200;
reply.data = profiles;
}
} else {
getProfile = this.controller.getProfile(profileId);
if (!!getProfile && (this.req.role === this.ROLE.ADMIN || (this.req.role === this.ROLE.USER && this.req.user === getProfile.id))) {
// do not send password (also role if user is not admin)
if (this.req.role === this.ROLE.ADMIN) {
excl = [];
} else {
excl = ["role"];
}
reply.code = 200;
reply.data = this.controller.safeProfile(getProfile);
} else {
reply.code = 404;
reply.error = "Profile not found.";
}
}
return reply;
},
createProfile: function() {
var reply = {
error: null,
data: null,
code: 500
},
reqObj,
profile,
uniqueEmail = [],
uniqueLogin = [];
try {
reqObj = JSON.parse(this.req.body);
} catch (ex) {
reply.error = ex.message;
return reply;
}
uniqueEmail = _.filter(this.controller.profiles, function(p) {
return p.email !== '' && p.email === reqObj.email;
});
uniqueLogin = _.filter(this.controller.profiles, function(p) {
return p.login !== '' && p.login === reqObj.login;
});
if (uniqueEmail.length > 0) {
reply.code = 409;
reply.error = 'nonunique_email';
} else if (uniqueLogin.length > 0) {
reply.code = 409;
reply.error = 'nonunique_user';
} else {
_.defaults(reqObj, {
role: null,
name: 'User',
email: '',
lang: 'en',
dashboard: [],
interval: 2000,
rooms: reqObj.role === this.ROLE.ADMIN ? [0] : [],
devices: [],
expert_view: false,
hide_all_device_events: false,
hide_system_events: false,
hide_single_device_events: [],
skin: '',
night_mode: false,
});
// skip OAuth2 and other metadata
reqObj = _.omit(reqObj, 'passwordConfirm', 'client_id', 'response_type', 'redirect_uri');
profile = this.controller.createProfile(reqObj);
if (profile !== undefined && profile.id !== undefined) {
reply.data = this.controller.safeProfile(profile);
reply.code = 201;
} else {
reply.code = 500;
reply.error = "Profile creation error";
}
}
return reply;
},
createOAuth2Profile: function() {
var reply = {
error: null,
data: null,
code: 500
},
reqObj,
profile,
profileReply,
zbwToken,
sid,
oauthReply,
authToken,
clientId;
// check that find.z-wave.me token is present
if (this.req.headers['Cookie']) {
var zbwCookie = this.req.headers['Cookie'].split(";").map(function(el) { return el.trim().split("="); }).filter(function(el) { return el[0] === "ZBW_SESSID" })[0];
if (zbwCookie) zbwToken = zbwCookie[1];
}
if (!zbwToken) {
reply.code = 405;
reply.error = "This method must be called thru find.z-wave.me";
return reply;
}
try {
reqObj = JSON.parse(this.req.body);
clientId = reqObj.client_id;
redirectUri = reqObj.redirect_uri;
responseType = reqObj.response_type;
} catch (ex) {
reply.code = 500;
reply.error = ex.message;
return reply;
}
profileReply = this.createProfile();
if (profileReply.code !== 200 && profileReply.code !== 201) return profileReply;
// profileReply.data is a safe copy, so get the original profile for checkIn
profile = _.find(this.controller.profiles, function (_profile) {
return _profile.id == profileReply.data.id;
});
// create permanent auth token for this user
sid = this.controller.auth.checkIn(profile, this.req, true);
data = {
access_token: zbwToken + "/" + sid,
client_id: clientId,
redirect_uri: redirectUri,
response_type: responseType
}
oauthReply = http.request({
url: "https://oauth2.z-wave.me:5000/saveToken",
method: "POST",
async: false,
headers: {
'Content-Type':'application/json'
},
data: JSON.stringify(data)
});
if (oauthReply.status != 200) {
this.removeProfile(profile.id); // revert creation of the user
reply.code = oauthReply.status;
reply.error = oauthReply.statusText;
return reply
}
authCode = oauthReply.data.auth_code;
if (!authCode) {
this.removeProfile(profile.id); // revert creation of the user
reply.code = 500;
reply.error = "OAuth2 auth token is empty";
return reply
}
reply.code = 200;
reply.data = {
auth_code: authCode
};
return reply;
},
updateProfile: function(profileId) {
var reply = {
error: null,
data: null,
code: 500
},
reqObj,
profile = _.clone(this.controller.getProfile(profileId)), // clone to allow check changes in controller.updateProfile
uniqueProfProps = [];
if (profile && (this.req.role === this.ROLE.ADMIN || (this.req.role === this.ROLE.USER && this.req.user === profile.id))) {
reqObj = JSON.parse(this.req.body);
if (profile.id === this.req.user && profile.role === this.ROLE.ADMIN && reqObj.role !== this.ROLE.ADMIN) {
reply.code = 403;
reply.error = "Revoking self Admin priviledge is not allowed.";
} else {
// check that e-mail is unique or empty
uniqueProfProps = _.filter(this.controller.profiles, function(p) {
return (p.email !== '' && p.email === reqObj.email) &&
p.id !== profileId;
});
if (uniqueProfProps.length === 0) {
// only Admin can change critical parameters
if (this.req.role === this.ROLE.ADMIN) {
// id is never changeable
// login is changed by updateProfileAuth()
profile.role = reqObj.role;
profile.rooms = reqObj.rooms.indexOf(0) === -1 && reqObj.role === this.ROLE.ADMIN ? reqObj.rooms.push(0) : reqObj.rooms;
profile.devices = reqObj.devices || [];
profile.expert_view = reqObj.expert_view;
profile.beta = reqObj.beta;
}
// could be changed by user role
profile.name = reqObj.name; // profile name
profile.interval = reqObj.interval; // update interval from ui
profile.hide_system_events = reqObj.hide_system_events;
profile.hide_all_device_events = reqObj.hide_all_device_events;
profile.lang = reqObj.lang;
profile.dashboard = reqObj.dashboard;
profile.hide_single_device_events = reqObj.hide_single_device_events;
profile.email = reqObj.email;
profile.night_mode = reqObj.night_mode;
profile = this.controller.updateProfile(profile, profile.id);
if (profile !== undefined && profile.id !== undefined) {
reply.data = this.controller.safeProfile(profile);
reply.code = 200;
} else {
reply.code = 500;
reply.error = "Profile was not created";
}
} else {
reply.code = 409;
reply.error = 'nonunique_email';
}
}
} else {
reply.code = 404;
reply.error = "Profile not found.";
}
return reply;
},
// different pipe for updating authentication values
updateProfileAuth: function(profileId) {
var self = this,
reply = {
error: null,
data: null,
code: 500
},
reqObj,
profile = this.controller.getProfile(profileId),
uniqueLogin = [],
reqToken = this.req.reqObj.hasOwnProperty("token") ? this.req.reqObj.token : null,
tokenObj = {};
reqObj = JSON.parse(this.req.body);
if (profile && (this.req.role === this.ROLE.ADMIN || (this.req.role === this.ROLE.USER && this.req.user === profile.id))) {
uniqueLogin = _.filter(this.controller.profiles, function(p) {
if (self.req.role === self.ROLE.ADMIN && self.req.user !== parseInt(reqObj.id, 10)) {
return p.login !== '' && p.login === reqObj.login && p.id !== parseInt(reqObj.id, 10);
} else {
return p.login !== '' && p.login === reqObj.login && p.id !== self.req.user;
}
});
if (uniqueLogin.length < 1) {
profile = this.controller.updateProfileAuth(reqObj, profileId);
if (!!profile && profile.id !== undefined) {
reply.data = this.controller.safeProfile(profile);
reply.code = 200;
} else {
reply.code = 500;
reply.error = "Was not able to update password.";
}
} else {
reply.code = 409;
reply.error = 'nonunique_user';
}
} else if (this.req.role === this.ROLE.ANONYMOUS && profileId && !!reqToken) {
tokenObj = self.controller.auth.getForgottenPwdToken(reqToken);
if (tokenObj && !!tokenObj) {
profile = this.controller.updateProfileAuth(reqObj, profileId);
if (!!profile && profile.id !== undefined) {
// remove forgotten token
self.controller.auth.removeForgottenPwdEntry(reqToken);
reply.code = 200;
} else {
reply.code = 500;
reply.error = "Was not able to update password.";
}
} else {
reply.code = 404;
reply.error = "Token not found.";
}
} else {
reply.code = 403;
reply.error = "Forbidden.";
}
return reply;
},
restorePassword: function(profileId) {
var self = this,
reply = {
error: null,
data: null,
code: 500
},
reqObj = typeof this.req.body !== 'object' ? JSON.parse(this.req.body) : this.req.body,
reqToken = this.req.query.hasOwnProperty("token") ? this.req.query.token : null,
profile,
emailExists = [],
tokenObj;
if (reqObj.email) {
emailExists = _.filter(self.controller.profiles, function(profile) {
return profile.email !== '' && profile.email === reqObj.email;
});
}
if (reqToken === null && emailExists.length > 0 && !profileId) {
try {
var tkn = crypto.guid(),
success = self.controller.auth.forgottenPwd(reqObj.email, tkn);
if (success) {
reply.data = {
token: tkn
};
reply.code = 200;
} else {
reply.error = "Token request for e-mail already exists.";
reply.code = 409;
}
} catch (e) {
reply.code = 500;
reply.error = "Internal server error.";
}
} else if (!!reqToken && emailExists.length < 1 && !profileId) {
try {
tokenObj = self.controller.auth.getForgottenPwdToken(reqToken);
if (tokenObj && !!tokenObj) {
profile = _.filter(self.controller.profiles, function(p) {
return p.email === tokenObj.email;
});
if (profile[0]) {
reply.code = 200;
reply.data = {
userId: profile[0].id
};
} else {
reply.code = 404;
reply.error = "User not found.";
}
} else {
reply.code = 404;
reply.error = "Token not found.";
}
} catch (e) {
reply.code = 500;
reply.error = "Internal server error.";
}
} else if (!!reqToken && emailExists.length < 1 && profileId) {
profile = self.controller.updateProfileAuth(reqObj, profileId);
if (!!profile && profile.id !== undefined) {
reply.code = 200;
} else {
reply.code = 500;
reply.error = "Wasn't able to update password.";
}
} else {
reply.code = 404;
reply.error = "Email not found.";
}
return reply;
},
removeProfile: function(profileId) {
var reply = {
error: null,
data: null,
code: 500
},
profile = this.controller.getProfile(profileId);
if (profile) {
// It is not possible to delete own profile
if (profile.id !== this.req.user) {
this.controller.removeProfile(profileId);
reply.data = null;
reply.code = 204;
} else {
reply.code = 403;
reply.error = "Deleting own profile is not allowed.";
}
} else {
reply.code = 404;
reply.error = "Profile not found";
}
return reply;
},
removeOwnProfile: function() {
var reply = {
error: null,
data: null,
code: 500
},
profile = this.controller.getProfile(this.req.user);
if (profile) {
// It is possible to delete own profile if the role is USER
if (this.req.role === profile.role) {
if (profile.authTokens.length == 1) {
// remove full profile
this.controller.removeProfile(this.req.user);
reply.data = null;
reply.code = 204;
} else if (profile.authTokens.length > 1) {
// remove single token
this.controller.removeToken(profile, this.req.token)
reply.data = null;
reply.code = 204;
} else {
reply.code = 404;
reply.error = "No tokens found - how have you logged in?";
}
} else {
reply.code = 403;
reply.error = "Deleting is possible only for own user profile.";
}
} else {
reply.code = 404;
reply.error = "Profile not found";
}
return reply;
},
removeToken: function(profileId, token) {
var reply = {
error: null,
data: null,
code: 500
},
profile = this.controller.getProfile(profileId);
if (profile) {
// Manage own tokens for users or any token for admin
if (profile.id === this.req.user && this.req.role === this.ROLE.USER || this.req.role === this.ROLE.ADMIN) {
if (this.controller.removeToken(profile, token)) {
reply.data = null;
reply.code = 204;
} else {
reply.code = 404;
reply.error = "Token not found";
}
} else {
reply.code = 403;
reply.error = "Permission denied";
}
} else {
reply.code = 404;
reply.error = "Profile not found";
}
return reply;
},
permanentToken: function(profileId, token) {
var reply = {
error: null,
data: null,
code: 500
},
profile = this.controller.getProfile(profileId);
if (profile) {
// Manage own tokens for users or any token for admin
if (profile.id === this.req.user && this.req.role === this.ROLE.USER || this.req.role === this.ROLE.ADMIN) {
if (this.controller.permanentToken(profile, token)) {
reply.data = null;
reply.code = 204;
} else {
reply.code = 404;
reply.error = "Token not found";
}
} else {
reply.code = 403;
reply.error = "Permission denied";
}
} else {
reply.code = 404;
reply.error = "Profile not found";
}
return reply;
},
getQRCodeString: function(profileId) {
var reply = {
error: null,
data: null,
code: 500
},
profile = this.controller.getProfile(profileId);
try {
var reqObj = parseToObject(this.req.body);
} catch (e) {
return reply.error = e.message;
}
if (profile) {
if (this.req.role === this.ROLE.ADMIN || (this.req.role === this.ROLE.USER && this.req.user === profileId)) {
var pwd_check = reqObj.password ? (!profile.salt && profile.password === reqObj.password) || (profile.salt && profile.password === hashPassword(reqObj.password, profile.salt)) : false;
if (pwd_check) {
var qrcode_str = this.controller.getQRCodeData(profile, reqObj.password);
if (qrcode_str !== undefined) {
reply.code = 200;
reply.data = qrcode_str;
} else {
reply.code = 500;
}
} else {
reply.error = "wrong_password";
reply.code = 500;
}
} else {
reply.error = "Forbidden";
reply.code = 403;
}
} else {
reply.code = 404;
reply.error = "Profile not found";
}
return reply;
},
/* Generating a local access token for the user. */
generateLocalAccessToken: function (profileId) {
var reply = {
error: null,
data: null,
code: 500
};
var profile = _.find(this.controller.profiles, function (_profile) {
return _profile.id === profileId;
});
if (profile) {
var sid = this.controller.auth.checkIn(profile, this.req, true);
var remoteId = this.controller.getRemoteId();
reply.code = 200;
reply.data = {
token: sid,
remoteId: remoteId
}
} else {
reply.code = 404;
reply.error = "Profile not found";
}
return reply;
},
notificationFilteringGet: function() {
var reply = {
error: null,
data: null,
code: 500
},
self = this;
var userDevices = this.controller.devicesByUser(this.req.user).map(function(dev) { return dev.id; });
var nfInstance = this.controller.listInstances().filter(function(i) { return i.moduleId === "NotificationFiltering"})[0]; // dirty hack - think about exported function by NotificationFiltering app
if (nfInstance) {
var devsStruct = [];
var arr = nfInstance.params.rules.filter(function(rule) {
var channel = self.controller.getNotificationChannel(rule.channel);
return false ||
(rule.recipient_type === "user" && rule.user == self.req.user) || // non-strict == because might be as string in module params
(rule.recipient_type === "channel" && channel && channel.user == self.req.user); // non-strict == because might be as string in module params
}).forEach(function(rule) { // flatten structure
rule.devices.forEach(function(devStruct) {
if (userDevices.indexOf(devStruct[devStruct["dev_filter"]]["dev_select"]) > -1) { // filter devices by allowed list
var _devStruct = _.clone(devStruct);
_devStruct.channel = rule.recipient_type === "channel" ? rule.channel : null;
devsStruct.push(_devStruct);
}
});
});
reply.data = devsStruct;
reply.code = 200;
} else {
reply.code = 501;
reply.error = "Not implemented. Activate NotificationFilter app";
}
return reply;
},
notificationFilteringSet: function() {
var reply = {
error: null,
data: null,
code: 500
},
self = this;
var userConfig = [];
try {
var reqObj = parseToObject(this.req.body);
// Transform to NotificationFiltring format
// Do sanity check not to let user break global NotificationFiltring config
reqObj.forEach(function(rule) {
var channel = rule.channel;
rule.channel = undefined;
if (!rule["dev_filter"] || !rule[rule["dev_filter"]]["dev_select"]) return;
userConfig.push({
recipient_type: channel ? "channel" : "user",
user: channel ? undefined : self.req.user,
channel: channel ? channel : undefined,
logLevel: "",
devices: [rule]
});
});
} catch (e) {
return reply.error = e.message;
}
this.controller.emit('notificationFiltering.userConfigUpdate', this.req.user, userConfig);
reply.code = 200;
return reply;
},
notificationChannelsGet: function(all) {
var reply = {
error: null,
data: null,
code: 500
},
self = this;
var channels = this.controller.notificationChannels;
reply.data = Object.keys(channels).map(function(ch) {
var profile = self.controller.getProfile(channels[ch].user);
return _.extend({id: ch, userName: profile ? profile.name : "-" }, channels[ch]);
}).filter(function(ch) {
return ch.user == self.req.user || (all && self.req.role === self.ROLE.ADMIN);
});
reply.code = 200;
return reply;
},
notificationChannelsGetAll: function() {
return this.notificationChannelsGet(true);
},
// namespaces
listNamespaces: function() {
var reply = {
error: null,
data: null,
code: 500
},
nspc;
nspc = this.controller.namespaces;
if (_.isArray(nspc) && nspc.length > 0) {
reply.data = nspc;
reply.code = 200;
} else {
reply.code = 404;
reply.error = "Namespaces array is null";
}
return reply;
},
getNamespaceFunc: function(namespaceId) {
var reply = {
error: null,
data: null,
code: 500
},
namespace;
namespace = this.controller.getListNamespaces(namespaceId, this.controller.namespaces);
if (!namespace || (_.isArray(namespace) && namespace.length < 1)) {
reply.code = 404;
reply.error = "No namespaces found with this path: " + namespaceId;
} else {
reply.data = namespace;
reply.code = 200;
}
return reply;
},
// restart
restartController: function(profileId) {
var reply = {
error: null,
data: null,
code: 200
};
this.controller.restart();
return reply;
},
loadModuleMedia: function(moduleName, fileName) {
var reply = {
error: null,
data: null,
code: 200
},
obj, _obj;
if ((moduleName !== '' || !!moduleName || moduleName) && (fileName !== '' || !!fileName || fileName)) {
obj = this.controller.loadModuleMedia(moduleName, fileName);
if (obj && obj.data === "") { // for folder we will get empty - try to open index.html
_obj = this.controller.loadModuleMedia(moduleName, fileName + "/index.html");
if (_obj && !!_obj.data) {
obj = _obj;
}
}
if (!this.controller.modules[moduleName]) {
reply.code = 404;
reply.error = "Can't load file from app because app '" + moduleName + "' was not found.";
return reply;
} else if (obj !== null) {
this.res.status = 200;
this.res.headers = {
"Content-Type": obj.ct
};
this.res.body = obj.data;
return null; // let handleRequest take this.res as is
} else {
reply.code = 500;
reply.error = "Failed to load file from module.";
return reply;
}
} else {
reply.code = 400;
reply.error = "Incorrect app or file name";
return reply;
}
},
loadImage: function(imageName) {
var reply = {
error: null,
data: null,
code: 200
},
data;
data = this.controller.loadImage(imageName);
if (data !== null) {
this.res.status = 200;
this.res.headers = {
"Content-Type": "image/*"
};
this.res.body = data;
return null; // let handleRequest take this.res as is
} else {
reply.code = 500;
reply.error = "Failed to load file.";
return reply;
}
},
uploadFile: function() {
var reply = {
error: null,
data: null,
code: 200
},
file;
if (this.req.method === "POST" && this.req.body) {
for (prop in this.req.body) {
if (this.req.body[prop]['content']) {
file = this.req.body[prop];
}
}
if (_.isArray(file)) {
file = file[0];
}
if (file && file.name && file.content || (_.isArray(file) && file.length > 0)) {
if (~file.name.indexOf('.csv') && typeof Papa === 'object') {
var csv = null;
Papa.parse(file.content, {
header: true,
dynamicTyping: true,
complete: function(results) {
csv = results;
}
});
if (!!csv) {
saveObject(file.name, csv, true);
}
} else {
// Create Base64 Object
saveObject(file.name, Base64.encode(file.content), true);
}
reply.code = 200;
reply.data = file.name;
} else {
reply.code = 500;
reply.error = "Failed to upload file";
}
} else {
reply.code = 400;
reply.error = "Invalid request";
}
return reply;
},
backup: function() {
var self = this,
reply = {
error: null,
data: null,
code: 500
};
var now = new Date();
// create a timestamp in format yyyy-MM-dd-HH-mm
var ts = getHRDateformat(now);
try {
var backupJSON = self.controller.createBackup();
reply.headers = {
"Content-Type": "application/octet-stream", // application/x-download octet-stream
"Content-Disposition": "attachment; filename=z-way-backup-" + ts + ".zab"
};
reply.code = 200;
reply.data = Base64.encode(JSON.stringify(backupJSON));
} catch (e) {
reply.code = 500;
reply.error = e.toString();
}
return reply;
},
restore: function() {
var self = this,
reqObj,
reply = {
error: null,
data: null,
code: 500
},
result = "",
langfile = this.controller.loadMainLang(),
dontSave = this.controller.getIgnoredStorageFiles([
"__ZWay",
"__ZBee",
"__EnOcean",
"__userModules",
"__userSkins"
]);
function waitForInstallation(allreadyInstalled, reqKey) {
var d = Date.now() + 300000; // wait not more than 5 min
while (Date.now() < d && allreadyInstalled.length <= reqObj.data[reqKey].length) {
if (allreadyInstalled.length === reqObj.data[reqKey].length) {
break;
}
processPendingCallbacks();
}
if (allreadyInstalled.length === reqObj.data[reqKey].length) {
// success
reply.code = 200;
}
}
// get flag that network information should be overwritten
allowTopoRestore = this.req.body.hasOwnProperty("overwriteNetwork") ? retBoolean(this.req.body.overwriteNetwork) : false;
try {
function utf8Decode(bytes) {
var chars = [];
for (var i = 0; i < bytes.length; i++) {
chars[i] = bytes.charCodeAt(i);
}
return chars;
}
reqObj = parseToObject(this.req.body.backupFile.content);
if (typeof reqObj.data === 'string') {
// new .zab files are base64 encoded, while old are not
decodeData = Base64.decode(reqObj.data);
// to JSON
reqObj.data = JSON.parse(decodeData);
}
// check if data is not empty
if (!reqObj.data) {
// missing file
reply.code = 400;
reply.error = "Bad Request. Please input a .zab backup file.";
return reply;
}
// stop the controller
this.controller.stop();
for (var obj in reqObj.data) {
if (dontSave.indexOf(obj) === -1) {
saveObject(obj, reqObj.data[obj], true);
console.log('Restore', obj, '... done');
}
}
// start controller with reload flag to apply config.json
this.controller.start(true);
// restore Z-Wave, Zigbee and EnOcean
!!reqObj.data["__ZWay"] && Object.keys(reqObj.data["__ZWay"]).forEach(function(zwayName) {
var zwayData = utf8Decode(reqObj.data["__ZWay"][zwayName]);
global.ZWave[zwayName] && global.ZWave[zwayName].zway.controller.Restore(zwayData, allowTopoRestore);
});
/* TODO
!!reqObj.data["__ZBee"] && Object.keys(reqObj.data["__ZBee"]).forEach(function(zbeeName) {
var zbeeData = utf8Decode(reqObj.data["__ZBee"][zbeeName]);
global.Zigbee[zbeeName] && global.Zigbee[zbeeName].zbee.controller.Restore(zbeeData, allowTopoRestore);
});
*/
/* TODO
!!reqObj.data["__EnOcean"] && reqObj.data["__EnOcean"].forEach(function(zenoName) {
// global.EnOcean[zenoName] && global.EnOcean[zenoName].zeno.Restore(reqObj.data["__EnOcean"][zenoName]);
});
*/
// install userModules
if (reqObj.data["__userModules"]) {
var installedModules = [];
_.forEach(reqObj.data["__userModules"], function(entry) {
http.request({
url: 'https://developer.z-wave.me/?uri=api-module-archive/' + entry.name,
method: 'GET',
async: true,
success: function(res) {
var archiv = [],
item = {
name: entry.name
},
location = 'modules/' + entry.name,
overwriteCoreModule = false;
if (res.data.data && res.data.data.length > 0) {
archiv = _.filter(res.data.data, function(appEntry) {
return appEntry.version === entry.version.toString();
})
// check if already loaded module is a core module
coreModule = self.controller.modules[entry.name] && self.controller.modules[entry.name].meta ? (self.controller.modules[entry.name].meta.location === location) : false;
// check if version of core module isn't higher than the restored one
if (coreModule) {
overwriteCoreModule = has_higher_version(entry.version, self.controller.modules[entry.name].meta.version);
}
// if achive was found try to download it
if (archiv.length > 0 && (!coreModule || (coreModule && overwriteCoreModule))) {
console.log('Restore userModule', archiv[0].modulename, 'v' + archiv[0].version);
result = self.controller.installModule('https://developer.z-wave.me/archiv/' + archiv[0].archiv, archiv[0].modulename);
item.status = result;
if (result === "done") {
loadSuccessfully = self.controller.reinitializeModule(entry.name, 'userModules/', true);
if (!loadSuccessfully) {
self.controller.addNotification("warning", langfile.zaap_war_restart_necessary + ' :: ' + entry.name + ' ' + 'v' + archiv[0].version, "core", "AppInstaller");
}
} else {
self.controller.addNotification("warning", langfile.zaap_err_app_install + ' :: ' + entry.name + ' ' + 'v' + archiv[0].version, "core", "AppInstaller");
}
} else {
// downlaod latest if it isn't already there
if (overwriteCoreModule) {
console.log(entry.name + ':', 'No archive with this version found. Install latest ...');
result = self.controller.installModule('https://developer.z-wave.me/modules/' + entry.name + '.tar.gz', entry.name);
item.status = result;
if (result === "done") {
self.controller.reinitializeModule(entry.name, 'userModules/', false);
self.controller.addNotification("warning", langfile.zaap_war_app_installed_corrupt_instance + ' :: ' + entry.name, "core", "AppInstaller");
} else {
self.controller.addNotification("error", langfile.zaap_err_app_install + ' :: ' + entry.name, "core", "AppInstaller");
}
} else {
self.controller.addNotification("warning", langfile.zaap_war_core_app_is_newer + ' :: ' + entry.name, "core", "AppInstaller");
item.status = 'failed';
}
}
} else {
self.controller.addNotification("error", langfile.zaap_err_no_archives + ' :: ' + entry.name, "core", "AppInstaller");
item.status = 'failed';
}
installedModules.push(item);
},
error: function(res) {
self.controller.addNotification("error", langfile.zaap_err_server + ' :: ' + entry.name + '::' + res.statusText, "core", "AppInstaller");
installedModules.push({
name: entry.name,
status: 'failed'
});
}
});
});
waitForInstallation(installedModules, "__userModules");
}
// install userSkins
if (reqObj.data["__userSkins"]) {
var installedSkins = [],
remoteSkins = [];
http.request({
// get online list of all existing modules first
url: 'https://developer.z-wave.me/?uri=api-skins',
method: 'GET',
async: true,
success: function(res) {
if (res.data.data) {
remoteSkins = res.data.data;
// download all skins that are online available
_.forEach(reqObj.data["__userSkins"], function(entry) {
var item = {
name: entry.name,
status: 'failed'
},
// check if backed up skin is in online list
remSkinObj = _.filter(remoteSkins, function(skin) {
return skin.name === entry.name;
});
if (remSkinObj[0]) {
index = _.findIndex(self.controller.skins, function(skin) {
return skin.name === entry.name;
});
try {
// install skin
result = self.controller.installSkin(remSkinObj[0], entry.name, index);
item.status = result;
} catch (e) {
self.controller.addNotification("error", langfile.zaap_err_no_archives + ' :: ' + entry.name, "core", "SkinInstaller");
}
}
installedSkins.push(item);
});
}
},
error: function(res) {
self.controller.addNotification("error", langfile.zaap_err_server + ' :: ' + res.statusText, "core", "SkinInstaller");
}
});
waitForInstallation(installedSkins, "__userSkins");
}
// success
reply.code = 200;
reply.data = {
userModules: installedModules,
userSkins: installedSkins
};
} catch (e) {
reply.error = e.toString();
}
return reply;
},
resetToFactoryDefault: function() {
var self = this,
langFile = this.controller.loadMainLang();
reply = {
error: null,
data: null,
code: 500
};
{
var backupCfg = loadObject("backupConfig"),
storageContentList = loadObject("__storageContent"),
defaultConfigExists = fs.stat('defaultConfigs/config.json'), // will be added during build - build depending
defaultConfig = {},
defaultSkins = [{
name: "default",
title: "Default",
description: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.",
version: "1.0.3",
icon: true,
author: "Martin Vach",
homepage: "http://www.zwave.eu",
active: true
}],
now = new Date();
try {
if (defaultConfigExists && defaultConfigExists.type !== 'dir' && defaultConfigExists.size > 0) {
defaultConfig = fs.loadJSON('defaultConfigs/config.json');
}
if (!!defaultConfig && !_.isEmpty(defaultConfig)) {
var ts = now.getFullYear() + "-";
ts += ("0" + (now.getMonth() + 1)).slice(-2) + "-";
ts += ("0" + now.getDate()).slice(-2) + "-";
ts += ("0" + now.getHours()).slice(-2) + "-";
ts += ("0" + now.getMinutes()).slice(-2);
console.log('Backup config ...');
// make backup of current config.json
saveObject('backupConfig' + ts, loadObject('config.json'), true);
// remove all active instances of moduleId
this.controller.instances.forEach(function(instance) {
if (instance.moduleId !== 'ZWave') {
self.controller.deleteInstance(instance.id);
}
});
if (typeof zway !== "undefined" && zway) {
// reset z-way controller
console.log('Reset Controller ...');
var d = Date.now() + 15000; // wait not more than 15 sec
zway.controller.SetDefault();
while (Date.now() < d && zway.controller.data.controllerState.value === 20) {
processPendingCallbacks();
}
// remove instances of ZWave at least
// filter for instances of ZWave
zwInstances = this.controller.instances.filter(function(instance) {
return instance.moduleId === 'ZWave';
}).map(function(instance) {
return instance.id;
});
// remove instance of ZWave
if (zwInstances.length > 0) {
zwInstances.forEach(function(instanceId) {
console.log('Remove ZWave instance: ' + instanceId);
self.controller.deleteInstance(instanceId);
});
}
}
console.log('Remove and unload userModules apps ...');
// unload and remove modules
Object.keys(this.controller.modules).forEach(function(className) {
var meta = self.controller.modules[className],
unload = '',
locPath = meta.location.split('/'),
success = false;
if (locPath[0] === 'userModules') {
console.log(className + ' remove it ...');
success = self.controller.uninstallModule(className);
if (success) {
console.log(className + ' has been successfully removed.');
} else {
console.log('Cannot remove app: ' + className);
self.addNotification("warning", langFile.zaap_err_uninstall_mod + ' ' + className, "core", "AutomationController");
}
}
});
// remove skins
_.forEach(this.controller.skins, function(skin) {
if (skin.name !== 'default') {
self.controller.uninstallSkin(skin.name);
}
});
// stop the controller
this.controller.stop();
// clean up storage
for (var ind in storageContentList) {
if (storageContentList[ind].indexOf('backupConfig') < 0 && !!storageContentList[ind]) {
saveObject(storageContentList[ind], null, true);
}
}
// clean up storageContent
if (__storageContent.length > 0) {
__saveObject("__storageContent", []);
__storageContent = [];
}
// set back to default config
saveObject('config.json', defaultConfig, true);
saveObject('userSkins.json', defaultSkins, true);
// start controller with reload flag to apply config.json
this.controller.start(true);
reply.code = 200;
setTimeout(function() {
self.doLogout();
}, 3000);
} else {
reply.code = 404;
reply.error = 'No default configuration file found.';
}
} catch (e) {
reply.error = 'Something went wrong. Error: ' + e.toString();
}
}
return reply;
},
getSkins: function() {
var reply = {
error: null,
data: null,
code: 500
};
if (this.controller.skins) {
reply.data = this.controller.skins;
reply.code = 200;
} else {
reply.error = 'failed_to_load_skins';
}
return reply;
},
getSkin: function(skinName) {
var reply = {
error: null,
data: null,
code: 500
};
if (this.controller.skins) {
index = _.findIndex(this.controller.skins, function(skin) {
return skin.name === skinName;
});
if (index > -1) {
reply.data = this.controller.skins[index];
reply.code = 200;
} else {
reply.code = 404;
reply.error = 'skin_not_exists';
}
} else {
reply.error = 'failed_to_load_skins';
}
return reply;
},
getActiveSkin: function() {
var reply = {
error: null,
data: null,
code: 500
};
if (this.controller.skins) {
index = _.findIndex(this.controller.skins, function(skin) {
return skin.active === true;
});
if (index > -1) {
reply.data = this.controller.skins[index];
reply.code = 200;
} else {
reply.code = 404;
reply.error = 'skin_not_exists';
}
} else {
reply.error = 'failed_to_load_skins';
}
return reply;
},
activateOrDeactivateSkin: function(skinName) {
var reply = {
error: null,
data: null,
code: 500
},
reqObj = parseToObject(this.req.body),
skin = null;
skin = this.controller.setSkinState(skinName, reqObj);
try {
if (!!skin) {
reply.data = skin;
reply.code = 200;
} else {
reply.code = 404;
reply.error = 'skin_not_exists';
}
} catch (e) {
reply.error = 'failed_to_load_skins';
reply.message = e.message;
}
return reply;
},
addOrUpdateSkin: function(skinName) {
var reply = {
error: 'skin_failed_to_install',
data: null,
code: 500
},
reqObj = parseToObject(this.req.body),
result = "",
skName = skinName || reqObj.name;
if (skName !== 'default') {
index = _.findIndex(this.controller.skins, function(skin) {
return skin.name === skName;
});
if ((index < 0 && this.req.method === 'POST') ||
(index > -1 && this.req.method === 'PUT' && skinName)) {
// download and install the skin
result = this.controller.installSkin(reqObj, skName, index);
if (result === "done") {
reply.code = 200;
reply.data = this.req.method === 'POST' ? "skin_installation_successful" : "skin_update_successful"; // send language key as response
reply.error = null;
}
} else if (this.req.method === 'POST' && !skinName) {
reply.code = 409;
reply.error = 'skin_from_url_already_exists';
} else if (this.req.method === 'PUT' && skinName) {
reply.code = 404;
reply.error = 'skin_not_exists';
}
} else {
reply.code = 403;
reply.error = 'No Permission';
}
return reply;
},
deleteSkin: function(skinName) {
var reply = {
error: 'skin_failed_to_delete',
data: null,
code: 500
},
uninstall = false;
if (skinName !== 'default') {
index = _.findIndex(this.controller.skins, function(skin) {
return skin.name === skinName;
});
if (index > -1) {
uninstall = this.controller.uninstallSkin(skinName);
if (uninstall) {
reply.code = 200;
reply.data = "skin_delete_successful"; // send language key as response
reply.error = null;
}
} else {
reply.code = 404;
reply.error = 'skin_not_exists';
}
} else {
reply.code = 403;
reply.error = 'No Permission';
}
return reply;
},
setDefaultSkin: function() {
var self = this,
reply = {
error: null,
data: null,
code: 500
};
try {
// deactivate all skins and set default skin to active: true
_.forEach(this.controller.skins, function(skin) {
skin.active = skin.name === 'default' ? true : false;
})
saveObject("userSkins.json", this.controller.skins, true);
reply.data = "Skin reset was successfull. You'll be logged out in 3, 2, 1 ...";
reply.code = 200;
// do logout
setTimeout(function() {
self.doLogout();
}, 3000);
} catch (e) {
reply.error = "Something went wrong.";
reply.message = e.message;
}
return reply;
},
getSkinTokens: function() {
var reply = {
error: null,
data: null,
code: 500
},
tokenObj = loadObject('skinTokens.json');
if (tokenObj === null) {
tokenObj = {
skinTokens: []
};
saveObject('skinTokens.json', tokenObj, true);
}
if (!!tokenObj) {
reply.data = tokenObj;
reply.code = 200;
} else {
reply.error = 'failed_to_load_skin_tokens';
}
return reply;
},
storeSkinToken: function() {
var reply = {
error: null,
data: null,
code: 500
},
reqObj = parseToObject(this.req.body),
tokenObj = loadObject('skinTokens.json');
if (reqObj && reqObj.token) {
if (tokenObj === null) {
tokenObj = {
skinTokens: [reqObj.token]
}
// save tokens
saveObject('skinTokens.json', tokenObj, true);
reply.data = tokenObj;
reply.code = 201;
} else if (!!tokenObj && tokenObj.skinTokens) {
if (tokenObj.skinTokens.indexOf(reqObj.token) < 0) {
// add new token id
tokenObj.skinTokens.push(reqObj.token);
// save tokens
saveObject('skinTokens.json', tokenObj, true);
reply.data = tokenObj;
reply.code = 201;
} else {
reply.code = 409;
reply.error = 'skin_token_not_unique';
}
}
} else {
reply.error = 'failed_to_load_skin_tokens';
}
return reply;
},
deleteSkinToken: function() {
var reply = {
error: null,
data: null,
code: 500
},
reqObj = parseToObject(this.req.body),
tokenObj = loadObject('skinTokens.json');
if (reqObj && reqObj.token && !!tokenObj && tokenObj.skinTokens) {
if (tokenObj.skinTokens.indexOf(reqObj.token) > -1) {
// add new token id
tokenObj.skinTokens = _.filter(tokenObj.skinTokens, function(token) {
return token !== reqObj.token;
});
// save tokens
saveObject('skinTokens.json', tokenObj, true);
reply.data = tokenObj;
reply.code = 200;
} else {
reply.code = 404;
reply.error = 'not_existing_skin_token';
}
} else {
reply.error = 'failed_to_load_skin_tokens';
}
return reply;
},
getIcons: function() {
var reply = {
error: null,
data: null,
code: 500
};
if (this.controller.icons) {
reply.data = this.controller.icons;
reply.code = 200;
} else {
reply.error = 'failed_to_load_icons';
}
return reply;
},
uploadIcon: function() {
var reply = {
error: 'icon_failed_to_install',
data: null,
code: 500
};
for (prop in this.req.body) {
if (this.req.body[prop]['content']) {
file = this.req.body[prop];
}
}
function utf8Decode(bytes) {
var chars = [];
for (var i = 0; i < bytes.length; i++) {
chars[i] = bytes.charCodeAt(i);
}
return chars;
}
function Uint8ToBase64(uint8) {
var i,
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
output = "",
temp, length;
var lookup = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
];
function tripletToBase64(num) {
return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
};
// go through the array every three bytes, we'll deal with trailing stuff later
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
output += tripletToBase64(temp);
}
// this prevents an ERR_INVALID_URL in Chrome (Firefox okay)
switch (output.length % 4) {
case 1:
output += '=';
break;
case 2:
output += '==';
break;
default:
break;
}
return output;
}
var data,
bytes = new Uint8Array(utf8Decode(file.content)),
re = /(?:\.([^.]+))?$/;
ext = re.exec(file.name)[1];
if (ext === 'gz') {
var gunzip = new Zlib.Gunzip(bytes);
data = gunzip.decompress();
} else {
data = bytes;
}
file.content = Uint8ToBase64(data);
result = this.controller.installIcon('local', file, 'custom', 'icon');
if (result.message === "done") {
reply.code = 200;
reply.data = result.files;
reply.error = null;
}
return reply
},
addOrUpdateIcons: function(iconName) {
var reply = {
error: 'icon_failed_to_install',
data: null,
code: 500
},
reqObj = parseToObject(this.req.body),
result = "",
icName = iconName || reqObj.name,
id = reqObj.id;
index = _.findIndex(this.controller.icons, function(icon) {
return icon.source === icName + "_" + id;
});
if (index === -1) {
// download and install the icon
result = this.controller.installIcon('remote', reqObj, icName, reqObj.id);
if (result.message === "done") {
reply.code = 200;
reply.data = result.files;
reply.error = null;
}
} else {
reply.code = 409;
reply.error = 'icon_from_url_already_exists';
}
return reply;
},
deleteIcons: function(iconName) {
var reply = {
error: 'icon_failed_to_delete',
data: null,
code: 500
},
uninstall = false;
var reqObj = typeof this.req.body === 'string' ? JSON.parse(this.req.body) : this.req.body;
this.controller.deleteCustomicon(iconName);
uninstall = this.controller.uninstallIcon(iconName);
if (uninstall) {
reply.code = 200;
reply.data = "icon_delete_successful";
reply.error = null;
}
return reply;
},
getTime: function() {
var reply = {
error: null,
data: null,
code: 500
},
tz = "",
now = new Date();
try {
var sys = system("sh automation/lib/timezone.sh getTZ");
sys.forEach(function(i) {
if (typeof i === 'string') {
tz = i.replace(/\n/g, '');
}
});
} catch (e) {}
if (now) {
reply.code = 200;
reply.data = {
localTimeUT: Math.round((now.getTime() + (now.getTimezoneOffset() * -60000)) / 1000), // generate timestamp with correct timezone offset
localTimeString: now.toLocaleString(),
localTimeZoneOffset: now.getTimezoneOffset() / 60,
localTimeZone: tz,
localGMT: now.toString().match(/([-\+][0-9]+)\s/)[1]
};
} else {
reply.error = 'Cannot get current date and time.';
}
return reply;
},
setTimezone: function() {
var self = this,
langfile = this.controller.loadMainLang();
reply = {
error: null,
data: null,
code: 500
},
data = {
"act": "set",
"tz": ""
};
reqObj = parseToObject(this.req.body);
data.tz = reqObj.timeZone;
try {
if (system("sh automation/lib/timezone.sh setTZ " + reqObj.timeZone)[0] !== 0) {
throw "Failed to set timezone";
} else {
reply.code = 200;
// reboot after 5 seconds
setTimeout(function() {
try {
console.log("Rebooting system ...");
system("reboot"); // reboot the box
} catch (e) {
self.controller.addNotification("error", langfile.zaap_err_reboot, "core", "SetTimezone");
}
}, 5000);
}
} catch (e) {
reply.error = res.statusText + "; " + e.toString();
}
return reply;
},
getRemoteId: function() {
var self = this,
reply = {
error: null,
data: null,
code: 500
};
try {
reply.code = 200;
reply.data = {
remote_id: self.controller.getRemoteId()
};
} catch (e) {
if (e.name === "service-not-available") {
reply.code = 503;
reply.error = e.message;
} else {
reply.code = 500;
reply.error = e.message;
}
}
return reply;
},
getIPAddress: function() {
var self = this,
reply = {
error: null,
data: null,
code: 500
},
ip = self.controller.getIPAddress();
if (ip) {
reply.code = 200;
reply.data = {
ip_address: ip
};
} else {
reply.code = 500;
reply.error = "syscommad-not-set";
}
return reply;
},
// set a timout for accessing firmware update tab of 8084
setWebifAccessTimout: function() {
var reply = {
error: null,
data: null,
code: 500
},
allowAcc = 0,
timeout = 900; // in s ~ 15 min
allowAcc = this.req.query.hasOwnProperty("allow_access") ? parseInt(this.req.query.allow_access, 10) : 0;
timeout = this.req.query.hasOwnProperty("timeout") ? parseInt(this.req.query.timeout, 10) : timeout;
if (allowAcc === 1 && timeout > 0 && timeout <= 1200) {
saveObject('8084AccessTimeout', timeout, true);
reply.code = 200;
reply.data = {
timeout: timeout
};
} else if (allowAcc === 0) {
saveObject('8084AccessTimeout', null, true);
reply.code = 200;
reply.data = {
timeout: null
};
} else {
reply.code = 400;
reply.error = 'Invalid Request';
}
return reply;
},
getFirstLoginInfo: function() {
var reply = {
error: null,
data: {},
code: 500
},
defaultProfile = [],
setLogin = {};
try {
defaultProfile = _.filter(this.controller.profiles, function(profile) {
return profile.login === 'admin' && profile.password === 'admin';
});
if ((!this.controller.config.first_start_up && defaultProfile.length > 0) || (defaultProfile.length > 0 && (typeof this.controller.config.firstaccess === 'undefined' || this.controller.config.firstaccess)) || (defaultProfile.length > 0 && !this.controller.config.firstaccess)) {
setLogin = this.setLogin(defaultProfile[0], this.req);
reply.headers = setLogin.headers; // set '/' Z-Way-Session root cookie
reply.data.defaultProfile = setLogin.data; // set login data of default profile
reply.data.firstaccess = true;
reply.data.defaultProfile.showWelcome = true;
} else {
reply.data.firstaccess = false;
}
reply.data.uuid = this.controller.getUUID();
reply.data.serial = this.controller.getSerial();
reply.data.mac = this.controller.getMACAddress();
reply.data.remote_id = this.controller.getRemoteId();
reply.data.ip_address = this.controller.getIPAddress();
reply.code = 200;
} catch (e) {
reply.data = null;
reply.error = e.message;
}
return reply;
},
getSystemInfo: function() {
var reply = {
error: null,
data: {},
code: 500
},
versionArr = [];
try {
versionArr = zway.controller.data.softwareRevisionVersion.value.substring(1).split('-');
version = versionArr[0] ? versionArr[0] : null;
majurity = versionArr[1] ? versionArr[1] : null;
reply.data = {
first_start_up: this.controller.config.first_start_up,
count_of_reconnects: this.controller.config.count_of_reconnects,
current_firmware: version,
current_firmware_majurity: majurity,
remote_id: this.controller.getRemoteId(),
uuid: this.controller.getUUID(),
serial: this.controller.getSerial(),
mac: this.controller.getMACAddress(),
firstaccess: this.controller.config.hasOwnProperty('firstaccess') ? this.controller.config.firstaccess : true
};
reply.code = 200;
} catch (e) {
reply.data = null;
reply.error = e.message;
}
return reply;
},
rebootBox: function() {
var self = this,
langfile = this.controller.loadMainLang();
reply = {
error: null,
data: null,
code: 500
};
// if reboot has flag firstaccess=true add showWelcome to controller config
if (this.req.query.hasOwnProperty('firstaccess') && this.req.query.firstaccess) {
this.controller.config.showWelcome = true;
this.controller.saveConfig(true);
}
// reboot after 5 seconds
setTimeout(function() {
try {
console.log("Rebooting system ...");
system("reboot"); // reboot the box
} catch (e) {
self.controller.addNotification("error", langfile.zaap_err_reboot, "core", "RebootBox");
}
}, 5000);
reply.code = 200;
reply.data = "System is rebooting ...";
return reply;
},
getWiF
gitextract_gic6ajyx/ ├── .jscsrc ├── .jshintrc ├── .syscommands ├── CHANGELOG.md ├── README.md ├── StorageProvider.js ├── Utils.js ├── Webserver.js ├── WebserverRequestRouter.js ├── ZAutomationAPIProvider.js ├── apiary.apib ├── classes/ │ ├── AuthController.js │ ├── AutomationController.js │ ├── AutomationModule.js │ ├── DevicesCollection.js │ └── VirtualDevice.js ├── defaultConfigs/ │ ├── README │ ├── config.json │ ├── config.json_WB │ ├── config.json_ttyACM0 │ ├── config.json_ttyACM0_ZBW-WD │ ├── config.json_ttyACM0_ZBW-no │ ├── config.json_ttyAMA0 │ ├── config.json_ttyAMA0_NonExpert │ ├── config.json_ttyS0 │ ├── config.json_ttyS0-JBox │ ├── config.json_ttyS0-ReHub │ ├── config.json_ttyS1 │ ├── config.json_ttyUSB0_ZBW-no_vDev-no │ └── config.json_windows ├── lang/ │ ├── cn.json │ ├── cz.json │ ├── de.json │ ├── en.json │ ├── es.json │ ├── fi.json │ ├── fr.json │ ├── it.json │ ├── pt.json │ ├── ru.json │ ├── se.json │ ├── sk.json │ └── sv.json ├── lib/ │ ├── BAOS_API_2011_01_29_001.js │ ├── IntelHex2bin.js │ ├── LimitedArray.js │ ├── base64.js │ ├── eventemitter2.js │ ├── underscore-umd-min.js │ └── underscore.js ├── main.js ├── modules/ │ ├── Alexa/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── AutoLock/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── AutoOff/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── BatteryPolling/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── BindDevices/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── Camera/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── CloudBackup/ │ │ ├── Readme.md │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── CodeDevice/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── CorrectValue/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── CounterTriggeringSensor/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── Cron/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── CustomUserCode/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── CustomUserCodeLoader/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── CustomUserCodeZWay/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── DecomposeRGB/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── DelayedScene/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── DeviceHistory/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── DummyDevice/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── EasyScripting/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ ├── compile.sh │ │ │ ├── postRender-with-comments.js │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── EdimaxSP1101/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── EdimaxSP2101/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── EnOcean/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── FosCam9805/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── FosCam9821/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── FosCam9826/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── FosCam9828/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── GlobalCache/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── GoogleHome/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── GroupDevices/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── HTTPDevice/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── HazardNotification/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── Heating/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── HomeKitGate/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── IfThen/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── ImportRemoteHA/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── InbandNotifications/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── InfoWidget/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── LightMotionRockerAutocontrol/ │ │ ├── index.js │ │ ├── lang/ │ │ │ └── en.json │ │ └── module.json │ ├── LightScene/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── LogicalRules/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── MQTTClient/ │ │ ├── index.js │ │ ├── lang/ │ │ │ └── en.json │ │ └── module.json │ ├── MatterGate/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── MobileAppSupport/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── MultilineSensor/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── NotificationChannelEmail/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ └── en.json │ │ └── module.json │ ├── NotificationFiltering/ │ │ ├── index.js │ │ ├── lang/ │ │ │ └── en.json │ │ └── module.json │ ├── NotificationSend/ │ │ ├── index.js │ │ ├── lang/ │ │ │ └── en.json │ │ └── module.json │ ├── OpenRemoteHelpers/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── OpenWeather/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── PhilioHW/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── PoppCam/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── RGB/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── RemoteAccess/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── RoundRobinScenes/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── Rules/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── Scenes/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── ScheduledScene/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── Schedules/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── Security/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── SecurityMode/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── SensorValueLogging/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── SensorsPolling/ │ │ ├── htdocs/ │ │ │ └── js/ │ │ │ └── postRender.js │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── SensorsPollingLogging/ │ │ ├── index.js │ │ └── module.json │ ├── SmartLight/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── Sonos/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── SwitchControlGenerator/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── SwitchPolling/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── TPLinkHS100/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── TPLinkHS110/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── TagOnOff/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── TamperAutoOff/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── TechnaxxTX65/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── TechnaxxTX66/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ └── module.json │ ├── TechnaxxTX67/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ └── en.json │ │ ├── module.json │ │ └── patchnotes.txt │ ├── ThermostatDevice/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── VistaCam/ │ │ ├── TVPIP320PIV1/ │ │ │ ├── index.js │ │ │ ├── lang/ │ │ │ │ ├── de.json │ │ │ │ └── en.json │ │ │ └── module.json │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── ZMEOpenWRT/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── ZMatter/ │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ └── module.json │ ├── ZWave/ │ │ ├── cmd_classes.json │ │ ├── index.js │ │ ├── lang/ │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── ru.json │ │ ├── module.json │ │ └── postfix.json │ └── Zigbee/ │ ├── index.js │ ├── lang/ │ │ ├── de.json │ │ ├── en.json │ │ └── ru.json │ └── module.json ├── modulesCategories.json ├── release.sh ├── router.js └── updateBackendConfig.js
SYMBOL INDEX (307 symbols across 107 files)
FILE: StorageProvider.js
function ZAutomationStorageWebRequest (line 14) | function ZAutomationStorageWebRequest () {
FILE: Utils.js
function inherits (line 25) | function inherits(ctor, superCtor) {
function in_array (line 42) | function in_array(array, value) {
function is_function (line 46) | function is_function(func) {
function has_key (line 50) | function has_key(obj, key) {
function get_values (line 54) | function get_values(obj) {
function byteArrayToString (line 64) | function byteArrayToString(data) {
function byteArrayToHexString (line 76) | function byteArrayToHexString(data) {
function generateSalt (line 84) | function generateSalt() {
function hashPassword (line 88) | function hashPassword(password, salt) {
function has_higher_version (line 92) | function has_higher_version(newVersion, currVersion) {
function changeObjectValue (line 113) | function changeObjectValue(obj, key, value) {
function getHRDateformat (line 260) | function getHRDateformat(now) {
function checkBoxtype (line 270) | function checkBoxtype(type) {
function parseToObject (line 285) | function parseToObject(object) {
function checkInternetConnection (line 289) | function checkInternetConnection(host_url) {
function retBoolean (line 323) | function retBoolean(boolean) {
function findSmallestNotAssignedIntegerValue (line 334) | function findSmallestNotAssignedIntegerValue (array, key) {
function transformPublicKeyToDSK (line 360) | function transformPublicKeyToDSK (publicKey) {
function dumpObject (line 375) | function dumpObject(obj, ancetors) {
function debugPrintStack (line 411) | function debugPrintStack() {
FILE: WebserverRequestRouter.js
function ZAutomationWebRequest (line 14) | function ZAutomationWebRequest() {
FILE: ZAutomationAPIProvider.js
function ZAutomationAPIWebRequest (line 16) | function ZAutomationAPIWebRequest(controller) {
function waitForInstallation (line 2384) | function waitForInstallation(allreadyInstalled, reqKey) {
function utf8Decode (line 2406) | function utf8Decode(bytes) {
function utf8Decode (line 3101) | function utf8Decode(bytes) {
function Uint8ToBase64 (line 3111) | function Uint8ToBase64(uint8) {
FILE: classes/AuthController.js
function AuthController (line 11) | function AuthController (controller) {
FILE: classes/AutomationController.js
function AutomationController (line 10) | function AutomationController() {
function wrap (line 56) | function wrap(self, func) {
function pushNamespaces (line 66) | function pushNamespaces(device, locationNspcOnly) {
function replaceNspcFilters (line 2553) | function replaceNspcFilters(moduleMeta, obj, keys) {
function getNspcFromFilters (line 2708) | function getNspcFromFilters(moduleMeta, nspcfilters) {
function findAllUsages (line 3706) | function findAllUsages(device) {
function findUsage (line 3733) | function findUsage(schema, config, device) {
FILE: classes/VirtualDevice.js
function inObj (line 103) | function inObj(obj, arr) {
function setObj (line 120) | function setObj(obj, arr, param) {
function findX (line 210) | function findX(obj, key) {
FILE: lib/BAOS_API_2011_01_29_001.js
function BaosLib (line 2) | function BaosLib()
FILE: lib/IntelHex2bin.js
function IntelHex2bin (line 2) | function IntelHex2bin(hex) {
FILE: lib/LimitedArray.js
function LimitedArray (line 6) | function LimitedArray(initial, saver, period, limit, filter) {
FILE: lib/eventemitter2.js
function init (line 9) | function init() {
function configure (line 16) | function configure(conf) {
function EventEmitter (line 32) | function EventEmitter(conf) {
function searchListenerTree (line 43) | function searchListenerTree(handlers, type, tree, i) {
function growListenerTree (line 149) | function growListenerTree(type, listener) {
function listener (line 241) | function listener() {
function recursivelyGarbageCollect (line 484) | function recursivelyGarbageCollect(root) {
FILE: lib/underscore-umd-min.js
function j (line 6) | function j(n,r){return r=null==r?n.length-1:+r,function(){for(var t=Math...
function _ (line 6) | function _(n){var r=typeof n;return"function"===r||"object"===r&&!!n}
function w (line 6) | function w(n){return void 0===n}
function A (line 6) | function A(n){return!0===n||!1===n||"[object Boolean]"===a.call(n)}
function x (line 6) | function x(n){var r="[object "+n+"]";return function(n){return a.call(n)...
function W (line 6) | function W(n,r){return null!=n&&f.call(n,r)}
function $ (line 6) | function $(n){return O(n)&&y(n)}
function C (line 6) | function C(n){return function(){return n}}
function K (line 6) | function K(n){return function(r){var t=n(r);return"number"==typeof t&&t>...
function J (line 6) | function J(n){return function(r){return null==r?void 0:r[n]}}
function Z (line 6) | function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e<t;++e)r[n[e]...
function nn (line 6) | function nn(n){if(!_(n))return[];if(p)return p(n);var r=[];for(var t in ...
function rn (line 6) | function rn(n,r){var t=nn(r),e=t.length;if(null==n)return!e;for(var u=Ob...
function tn (line 6) | function tn(n){return n instanceof tn?n:this instanceof tn?void(this._wr...
function en (line 6) | function en(n){return new Uint8Array(n.buffer||n,n.byteOffset||0,G(n))}
function on (line 6) | function on(n,r,t,e){if(n===r)return 0!==n||1/n==1/r;if(null==n||null==r...
function an (line 6) | function an(n){if(!_(n))return[];var r=[];for(var t in n)r.push(t);retur...
function fn (line 6) | function fn(n){var r=Y(n);return function(t){if(null==t)return!1;var e=a...
function jn (line 6) | function jn(n){for(var r=nn(n),t=r.length,e=Array(t),u=0;u<t;u++)e[u]=n[...
function _n (line 6) | function _n(n){for(var r={},t=nn(n),e=0,u=t.length;e<u;e++)r[n[t[e]]]=t[...
function wn (line 6) | function wn(n){var r=[];for(var t in n)D(n[t])&&r.push(t);return r.sort()}
function An (line 6) | function An(n,r){return function(t){var e=arguments.length;if(r&&(t=Obje...
function Mn (line 6) | function Mn(n){if(!_(n))return{};if(v)return v(n);var r=function(){};r.p...
function En (line 6) | function En(n){return U(n)?n:[n]}
function Bn (line 6) | function Bn(n){return tn.toPath(n)}
function Nn (line 6) | function Nn(n,r){for(var t=r.length,e=0;e<t;e++){if(null==n)return;n=n[r...
function In (line 6) | function In(n,r,t){var e=Nn(n,Bn(r));return w(e)?t:e}
function Tn (line 6) | function Tn(n){return n}
function kn (line 6) | function kn(n){return n=Sn({},n),function(r){return rn(r,n)}}
function Dn (line 6) | function Dn(n){return n=Bn(n),function(r){return Nn(r,n)}}
function Rn (line 6) | function Rn(n,r,t){if(void 0===r)return n;switch(null==t?3:t){case 1:ret...
function Fn (line 6) | function Fn(n,r,t){return null==n?Tn:D(n)?Rn(n,r,t):_(n)&&!U(n)?kn(n):Dn...
function Vn (line 6) | function Vn(n,r){return Fn(n,r,1/0)}
function Pn (line 6) | function Pn(n,r,t){return tn.iteratee!==Vn?tn.iteratee(n,r):Fn(n,r,t)}
function qn (line 6) | function qn(){}
function Un (line 6) | function Un(n,r){return null==r&&(r=n,n=0),n+Math.floor(Math.random()*(r...
function zn (line 6) | function zn(n){var r=function(r){return n[r]},t="(?:"+nn(n).join("|")+")...
function Qn (line 6) | function Qn(n){return"\\"+Gn[n]}
function Zn (line 6) | function Zn(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var o=Mn...
function er (line 6) | function er(n,r,t,e){if(e=e||[],r||0===r){if(r<=0)return e.concat(n)}els...
function ar (line 6) | function ar(n){return function(){return!n.apply(this,arguments)}}
function fr (line 6) | function fr(n,r){var t;return function(){return--n>0&&(t=r.apply(this,ar...
function lr (line 6) | function lr(n,r,t){r=Pn(r,t);for(var e,u=nn(n),o=0,i=u.length;o<i;o++)if...
function sr (line 6) | function sr(n){return function(r,t,e){t=Pn(t,e);for(var u=Y(r),o=n>0?0:u...
function hr (line 6) | function hr(n,r,t,e){for(var u=(t=Pn(t,e,1))(r),o=0,i=Y(n);o<i;){var a=M...
function yr (line 6) | function yr(n,r,t){return function(e,u,o){var a=0,f=Y(e);if("number"==ty...
function br (line 6) | function br(n,r,t){var e=(tr(n)?pr:lr)(n,r,t);if(void 0!==e&&-1!==e)retu...
function mr (line 6) | function mr(n,r,t){var e,u;if(r=Rn(r,t),tr(n))for(e=0,u=n.length;e<u;e++...
function jr (line 6) | function jr(n,r,t){r=Pn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,o=A...
function _r (line 6) | function _r(n){var r=function(r,t,e,u){var o=!tr(r)&&nn(r),i=(o||r).leng...
function xr (line 6) | function xr(n,r,t){var e=[];return r=Pn(r,t),mr(n,(function(n,t,u){r(n,t...
function Sr (line 6) | function Sr(n,r,t){r=Pn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,o=0...
function Or (line 6) | function Or(n,r,t){r=Pn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,o=0...
function Mr (line 6) | function Mr(n,r,t,e){return tr(n)||(n=jn(n)),("number"!=typeof t||e)&&(t...
function Br (line 6) | function Br(n,r){return jr(n,Dn(r))}
function Nr (line 6) | function Nr(n,r,t){var e,u,o=-1/0,i=-1/0;if(null==r||"number"==typeof r&...
function Tr (line 6) | function Tr(n){return n?U(n)?i.call(n):S(n)?n.match(Ir):tr(n)?jr(n,Tn):j...
function kr (line 6) | function kr(n,r,t){if(null==r||t)return tr(n)||(n=jn(n)),n[Un(n.length-1...
function Dr (line 6) | function Dr(n,r){return function(t,e,u){var o=r?[[],[]]:{};return e=Pn(e...
function qr (line 6) | function qr(n,r,t){return r in t}
function zr (line 6) | function zr(n,r,t){return i.call(n,0,Math.max(0,n.length-(null==r||t?1:r...
function Lr (line 6) | function Lr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null=...
function $r (line 6) | function $r(n,r,t){return i.call(n,null==r||t?1:r)}
function Jr (line 6) | function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=Pn(t,e));for(var u...
function Hr (line 6) | function Hr(n){for(var r=n&&Nr(n,Y).length||0,t=Array(r),e=0;e<r;e++)t[e...
function Xr (line 6) | function Xr(n,r){return n._chain?tn(r).chain():r}
function Yr (line 6) | function Yr(n){return mr(wn(n),(function(r){var t=tn[r]=n[r];tn.prototyp...
FILE: lib/underscore.js
function createReduce (line 178) | function createReduce(dir) {
function createPredicateIndexFinder (line 614) | function createPredicateIndexFinder(dir) {
function createIndexFinder (line 644) | function createIndexFinder(dir, predicateFind, sortedIndex) {
function collectNonEnumProps (line 909) | function collectNonEnumProps(obj, keys) {
FILE: main.js
function __saveObjectsNow (line 100) | function __saveObjectsNow() {
FILE: modules/Alexa/index.js
function Alexa (line 11) | function Alexa (id, controller) {
function pad (line 1275) | function pad(n) {return n<10 ? '0'+n : n}
function hsvToRgb (line 1345) | function hsvToRgb(h, s, v) {
FILE: modules/AutoLock/index.js
function AutoLock (line 15) | function AutoLock (id, controller) {
FILE: modules/AutoOff/index.js
function AutoOff (line 19) | function AutoOff (id, controller) {
FILE: modules/BatteryPolling/index.js
function BatteryPolling (line 17) | function BatteryPolling (id, controller) {
FILE: modules/BindDevices/index.js
function BindDevices (line 15) | function BindDevices (id, controller) {
FILE: modules/Camera/index.js
function Camera (line 16) | function Camera (id, controller) {
FILE: modules/CloudBackup/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender(control) {
FILE: modules/CloudBackup/index.js
function CloudBackup (line 11) | function CloudBackup (id, controller) {
FILE: modules/CodeDevice/index.js
function CodeDevice (line 15) | function CodeDevice (id, controller) {
FILE: modules/CorrectValue/index.js
function CorrectValue (line 17) | function CorrectValue (id, controller) {
FILE: modules/CounterTriggeringSensor/index.js
function CounterTriggeringSensor (line 15) | function CounterTriggeringSensor (id, controller) {
FILE: modules/Cron/index.js
function Cron (line 35) | function Cron (id, controller) {
FILE: modules/CustomUserCode/index.js
function CustomUserCode (line 17) | function CustomUserCode (id, controller) {
FILE: modules/CustomUserCodeLoader/index.js
function CustomUserCodeLoader (line 17) | function CustomUserCodeLoader (id, controller) {
FILE: modules/CustomUserCodeZWay/index.js
function CustomUserCodeZWay (line 17) | function CustomUserCodeZWay (id, controller) {
FILE: modules/DecomposeRGB/index.js
function DecomposeRGB (line 16) | function DecomposeRGB (id, controller) {
function levelToColor (line 34) | function levelToColor(command, args) {
function colorToLevel (line 47) | function colorToLevel(color) {
FILE: modules/DelayedScene/index.js
function DelayedScene (line 15) | function DelayedScene (id, controller) {
FILE: modules/DeviceHistory/index.js
function DeviceHistory (line 15) | function DeviceHistory (id, controller) {
FILE: modules/DummyDevice/index.js
function DummyDevice (line 15) | function DummyDevice (id, controller) {
FILE: modules/EasyScripting/htdocs/js/postRender-with-comments.js
function modulePostRender (line 1) | function modulePostRender(control) {
FILE: modules/EasyScripting/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender(C){function y(a,b,c){var e=null!=window.mozInn...
FILE: modules/EasyScripting/index.js
function EasyScripting (line 14) | function EasyScripting (id, controller) {
FILE: modules/EdimaxSP1101/index.js
function EdimaxSP1101 (line 17) | function EdimaxSP1101 (id, controller) {
FILE: modules/EdimaxSP2101/index.js
function EdimaxSP2101 (line 17) | function EdimaxSP2101 (id, controller) {
FILE: modules/EnOcean/index.js
function EnOcean (line 10) | function EnOcean (id, controller) {
function matchDevice (line 451) | function matchDevice(rorg, funcId, typeId) {
function binarySensor (line 458) | function binarySensor(dh, type, title, withTimeout, handler) {
function multilevelSensor (line 500) | function multilevelSensor(dh, type, scale, title) {
function rockerSwitch (line 532) | function rockerSwitch() {
function thermostat (line 636) | function thermostat(dh, type, scale, title) {
function binarySwitch (line 671) | function binarySwitch(dh, type, title, valToVDev, vDevToVal) {
function binarySensorGP (line 870) | function binarySensorGP(o, type, title) {
function binarySwitchGP (line 902) | function binarySwitchGP(o, i, type, title) {
FILE: modules/FosCam9805/index.js
function FosCam9805 (line 16) | function FosCam9805 (id, controller) {
FILE: modules/FosCam9821/index.js
function FosCam9821 (line 16) | function FosCam9821 (id, controller) {
FILE: modules/FosCam9826/index.js
function FosCam9826 (line 16) | function FosCam9826 (id, controller) {
FILE: modules/FosCam9828/index.js
function FosCam9828 (line 16) | function FosCam9828 (id, controller) {
FILE: modules/GlobalCache/index.js
function GlobalCache (line 15) | function GlobalCache (id, controller) {
FILE: modules/GoogleHome/index.js
function GoogleHome (line 11) | function GoogleHome (id, controller) {
FILE: modules/GroupDevices/index.js
function GroupDevices (line 18) | function GroupDevices (id, controller) {
FILE: modules/HTTPDevice/index.js
function HTTPDevice (line 15) | function HTTPDevice (id, controller) {
FILE: modules/HazardNotification/index.js
function HazardNotification (line 15) | function HazardNotification(id, controller) {
FILE: modules/Heating/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender(control) {
FILE: modules/Heating/index.js
function Heating (line 21) | function Heating(id, controller) {
function getTime (line 452) | function getTime(filterArray, compareString) {
FILE: modules/HomeKitGate/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender() {
FILE: modules/HomeKitGate/index.js
function HomeKitGate (line 15) | function HomeKitGate (id, controller) {
function onDeviceAddedCore (line 53) | function onDeviceAddedCore(vDevT) {
function getCurrentTemperature (line 357) | function getCurrentTemperature(nodeId) {
function getTargetTemperature (line 382) | function getTargetTemperature(nodeId) {
function getTargetMode (line 410) | function getTargetMode(nodeId) {
function getCurrentMode (line 418) | function getCurrentMode(nodeId) {
function exactColor (line 432) | function exactColor(vDev, valueName, value) {
function hsv (line 473) | function hsv(vDev){
function hsv2rgb (line 477) | function hsv2rgb(obj) {
function rgb2hsv (line 513) | function rgb2hsv(obj) {
function updateSkippedDevicesList (line 534) | function updateSkippedDevicesList() {
function removeFromHkDevicesArray (line 556) | function removeFromHkDevicesArray(vDevid) {
FILE: modules/IfThen/index.js
function IfThen (line 18) | function IfThen (id, controller) {
FILE: modules/ImportRemoteHA/index.js
function ImportRemoteHA (line 15) | function ImportRemoteHA (id, controller) {
FILE: modules/InbandNotifications/index.js
function InbandNotifications (line 16) | function InbandNotifications (id, controller) {
function getCustomIcon (line 44) | function getCustomIcon() {
function eventType (line 50) | function eventType(){
FILE: modules/InfoWidget/index.js
function InfoWidget (line 17) | function InfoWidget (id, controller) {
FILE: modules/LightMotionRockerAutocontrol/index.js
function LightMotionRockerAutocontrol (line 20) | function LightMotionRockerAutocontrol (id, controller) {
FILE: modules/LightScene/index.js
function LightScene (line 16) | function LightScene (id, controller) {
FILE: modules/LogicalRules/index.js
function LogicalRules (line 15) | function LogicalRules (id, controller) {
FILE: modules/MQTTClient/index.js
function MQTTClient (line 16) | function MQTTClient(id, controller) {
FILE: modules/MatterGate/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender() {
FILE: modules/MatterGate/index.js
function MatterGate (line 15) | function MatterGate (id, controller) {
function onDeviceAddedCore (line 51) | function onDeviceAddedCore(vDevT) {
function updateSkippedDevicesList (line 466) | function updateSkippedDevicesList() {
function removeFromMatterDevicesArray (line 488) | function removeFromMatterDevicesArray(vDevid) {
FILE: modules/MobileAppSupport/index.js
function MobileAppSupport (line 24) | function MobileAppSupport(id, controller) {
FILE: modules/MultilineSensor/index.js
function MultilineSensor (line 15) | function MultilineSensor (id, controller) {
FILE: modules/NotificationChannelEmail/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender() {
FILE: modules/NotificationChannelEmail/index.js
function NotificationChannelEmail (line 16) | function NotificationChannelEmail (id, controller) {
FILE: modules/NotificationFiltering/index.js
function NotificationFiltering (line 14) | function NotificationFiltering (id, controller) {
FILE: modules/NotificationSend/index.js
function NotificationSend (line 15) | function NotificationSend(id, controller) {
FILE: modules/OpenRemoteHelpers/index.js
function OpenRemoteHelpers (line 121) | function OpenRemoteHelpers (id, controller) {
FILE: modules/OpenWeather/index.js
function OpenWeather (line 18) | function OpenWeather (id, controller) {
FILE: modules/PhilioHW/index.js
function PhilioHW (line 15) | function PhilioHW (id, controller) {
FILE: modules/PoppCam/index.js
function PoppCam (line 16) | function PoppCam (id, controller) {
FILE: modules/RGB/index.js
function RGB (line 17) | function RGB (id, controller) {
function levelToColor (line 41) | function levelToColor(vDev) {
function colorToLevel (line 53) | function colorToLevel(color) {
FILE: modules/RemoteAccess/index.js
function RemoteAccess (line 15) | function RemoteAccess (id, controller) {
FILE: modules/RoundRobinScenes/index.js
function RoundRobinScenes (line 15) | function RoundRobinScenes (id, controller) {
FILE: modules/Rules/index.js
function Rules (line 17) | function Rules(id, controller) {
FILE: modules/Scenes/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender() {
FILE: modules/Scenes/index.js
function Scenes (line 19) | function Scenes(id, controller) {
FILE: modules/ScheduledScene/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender(control) {
function getWeekArray (line 15) | function getWeekArray() {
FILE: modules/ScheduledScene/index.js
function ScheduledScene (line 17) | function ScheduledScene (id, controller) {
FILE: modules/Schedules/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender(control) {
FILE: modules/Schedules/index.js
function Schedules (line 18) | function Schedules(id, controller) {
FILE: modules/Security/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender(control) {
function fillDropDown (line 86) | function fillDropDown(profiles, selectedMail, notificationID) {
FILE: modules/Security/index.js
function Security (line 12) | function Security(id, controller) {
FILE: modules/SecurityMode/index.js
function SecurityMode (line 16) | function SecurityMode (id, controller) {
FILE: modules/SensorValueLogging/index.js
function SensorValueLogging (line 17) | function SensorValueLogging (id, controller) {
FILE: modules/SensorsPolling/htdocs/js/postRender.js
function modulePostRender (line 1) | function modulePostRender() {
FILE: modules/SensorsPolling/index.js
function SensorsPolling (line 17) | function SensorsPolling (id, controller) {
FILE: modules/SensorsPollingLogging/index.js
function SensorsPollingLogging (line 20) | function SensorsPollingLogging (id, controller) {
FILE: modules/SmartLight/index.js
function SmartLight (line 14) | function SmartLight (id, controller) {
FILE: modules/Sonos/index.js
function Sonos (line 22) | function Sonos (id, controller) {
FILE: modules/SwitchControlGenerator/index.js
function SwitchControlGenerator (line 15) | function SwitchControlGenerator (id, controller) {
FILE: modules/SwitchPolling/index.js
function SwitchPolling (line 17) | function SwitchPolling (id, controller) {
FILE: modules/TPLinkHS100/index.js
function TPLinkHS100 (line 17) | function TPLinkHS100 (id, controller) {
FILE: modules/TPLinkHS110/index.js
function TPLinkHS110 (line 17) | function TPLinkHS110 (id, controller) {
FILE: modules/TagOnOff/index.js
function TagOnOff (line 15) | function TagOnOff (id, controller) {
FILE: modules/TamperAutoOff/index.js
function TamperAutoOff (line 16) | function TamperAutoOff (id, controller) {
FILE: modules/TechnaxxTX65/index.js
function TechnaxxTX65 (line 16) | function TechnaxxTX65 (id, controller) {
FILE: modules/TechnaxxTX66/index.js
function TechnaxxTX66 (line 16) | function TechnaxxTX66 (id, controller) {
FILE: modules/TechnaxxTX67/index.js
function TechnaxxTX67 (line 16) | function TechnaxxTX67 (id, controller) {
FILE: modules/ThermostatDevice/index.js
function ThermostatDevice (line 15) | function ThermostatDevice (id, controller) {
FILE: modules/VistaCam/index.js
function VistaCam (line 16) | function VistaCam (id, controller) {
FILE: modules/ZMEOpenWRT/index.js
function ZMEOpenWRT (line 18) | function ZMEOpenWRT (id, controller) {
FILE: modules/ZMatter/index.js
function ZMatter (line 28) | function ZMatter(id, controller) {
function scenesSupport (line 1137) | function scenesSupport(instId, cluster, minBtnNr, maxBtnNr, type) {
function setConfig (line 1171) | function setConfig(instId, parameter, value, size) {
function setCCData (line 1200) | function setCCData(instId, cluster, dataType, key, value) {
function setDeviceData (line 1231) | function setDeviceData(dataType, key, value) {
function renameNode (line 1254) | function renameNode(nodeName) {
function HSVtoRGB (line 1844) | function HSVtoRGB(h, s, v) {
function RGBtoHSV (line 1873) | function RGBtoHSV(r, g, b) {
function handleColor (line 1894) | function handleColor(type, arg) {
FILE: modules/ZWave/index.js
function ZWave (line 28) | function ZWave(id, controller) {
function RSSItoText (line 589) | function RSSItoText(rssiValue) {
function prepareRSSI (line 597) | function prepareRSSI(rssiPacket) {
function packetApplication (line 605) | function packetApplication(packet, packetType) {
function decodePayload (line 753) | function decodePayload(payload) {
function decToHex (line 808) | function decToHex(decimal) {
function createIncomingEntry (line 812) | function createIncomingEntry(packet) {
function createOutgoingEntry (line 825) | function createOutgoingEntry(packet) {
function safeInt (line 912) | function safeInt(string, defaultValue) {
function decStrToHexStr (line 922) | function decStrToHexStr(decimal) {
function parseWithoutProductType (line 931) | function parseWithoutProductType(entry) {
function parseWithZws2dskPrefix (line 940) | function parseWithZws2dskPrefix(entry) {
function checkHashSum (line 944) | function checkHashSum(entry, hash) {
function extractType (line 951) | function extractType(input) {
function block (line 965) | function block(source, start, count) {
function codeToDevice (line 973) | function codeToDevice(code) {
function strCodeToSecurity (line 1021) | function strCodeToSecurity(code) {
function parseTypes (line 1031) | function parseTypes(types) {
function parseWithProductType (line 1040) | function parseWithProductType(entry) {
function storeDsk (line 1060) | function storeDsk(self, dskEntry) {
function NetworkReorganization (line 1236) | function NetworkReorganization(that) {
function createBackup (line 1688) | function createBackup() {
function hexByteToStr (line 1805) | function hexByteToStr(n) {
function intToHexStr (line 1809) | function intToHexStr(value, size) {
function hexWordToStr (line 1812) | function hexWordToStr(n) {
function tagAttrValue (line 1816) | function tagAttrValue(name, value) {
function tagByte (line 1825) | function tagByte(name, value) {
function tagWord (line 1829) | function tagWord(name, value) {
function tagBool (line 1833) | function tagBool(name, value) {
function tagText (line 1837) | function tagText(name, value) {
function tagLangs (line 1844) | function tagLangs(name, values) {
function inNIF (line 1865) | function inNIF(id, nif, afterMark) {
function tagCC (line 1883) | function tagCC(id, version, supported, secure, nif) {
function hasFinished (line 2301) | function hasFinished() {
function setIncluded (line 3352) | function setIncluded(DSKCollection) {
function scenesSupport (line 4009) | function scenesSupport(instId, commandClass, minBtnNr, maxBtnNr, type) {
function setConfig (line 4043) | function setConfig(instId, parameter, value, size) {
function setCCData (line 4072) | function setCCData(instId, commandClass, dataType, key, value) {
function setDeviceData (line 4103) | function setDeviceData(dataType, key, value) {
function renameNode (line 4126) | function renameNode(nodeName) {
function handleColor (line 4801) | function handleColor(type, arg) {
function setProbeTypeAndIcon (line 5807) | function setProbeTypeAndIcon(defaults, notificationTypeId, eventTypeId) {
function createTiltVDev (line 5909) | function createTiltVDev(a_id) {
function valueToRSSI (line 6365) | function valueToRSSI(rssi) {
FILE: modules/Zigbee/index.js
function Zigbee (line 28) | function Zigbee(id, controller) {
function scenesSupport (line 1142) | function scenesSupport(instId, cluster, minBtnNr, maxBtnNr, type) {
function setConfig (line 1176) | function setConfig(instId, parameter, value, size) {
function setCCData (line 1205) | function setCCData(instId, cluster, dataType, key, value) {
function setDeviceData (line 1236) | function setDeviceData(dataType, key, value) {
function renameNode (line 1259) | function renameNode(nodeName) {
function HSVtoRGB (line 1849) | function HSVtoRGB(h, s, v) {
function RGBtoHSV (line 1878) | function RGBtoHSV(r, g, b) {
function handleColor (line 1899) | function handleColor(type, arg) {
FILE: updateBackendConfig.js
function getNewID (line 331) | function getNewID(id) {
function fixArray (line 376) | function fixArray(arr) {
function fixObject (line 391) | function fixObject(obj) {
Condensed preview — 454 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,869K chars).
[
{
"path": ".jscsrc",
"chars": 1856,
"preview": "{\n \"requireCurlyBraces\": [\"if\", \"else\", \"for\", \"while\", \"do\", \"try\", \"catch\", \"case\"],\n \"requireSpaceAfterKeywords\": ["
},
{
"path": ".jshintrc",
"chars": 362,
"preview": "{\n \"nonew\": true,\n \"curly\": true,\n \"noarg\": true,\n \"forin\": true,\n \"noempty\": true,\n \"eqeqeq\":true,\n \"strict\":tru"
},
{
"path": ".syscommands",
"chars": 283,
"preview": "cat /etc/z-way/box_type\nreboot\ncat /etc/timezone\nsh automation/lib/configAP.sh\nsh automation/lib/fetchLog.sh\nsh automati"
},
{
"path": "CHANGELOG.md",
"chars": 73953,
"preview": "## 10.10.2024 v5.0.1\nNew features:\n* Added externalUrl property in Camera app\nFixes:\n* Fixed screenUrl property in Camer"
},
{
"path": "README.md",
"chars": 2500,
"preview": "Z-Way Home Automation Engine\n====================================\n\n# Introduction #\n<a href=\"https://gitter.im/Z-Wave-Me"
},
{
"path": "StorageProvider.js",
"chars": 3853,
"preview": "/*** Main Automation storage module *****************************************\n\nVersion:\n--------------------------------"
},
{
"path": "Utils.js",
"chars": 9965,
"preview": "// Comon utilities and functions\n\nvar console = {\n\tlog: debugPrint,\n\twarn: debugPrint,\n\terror: debugPrint,\n\tdebug: debug"
},
{
"path": "Webserver.js",
"chars": 4635,
"preview": "/*** Initialize Webserver and Handlers *****************************************\n\n Version:\n ---------------------------"
},
{
"path": "WebserverRequestRouter.js",
"chars": 7001,
"preview": "/*** ZAutomationAPI Web Request Handler *****************************************\n\n Version:\n --------------------------"
},
{
"path": "ZAutomationAPIProvider.js",
"chars": 110413,
"preview": "/*** ZAutomationAPI Provider **************************************************\n\nVersion:\n------------------------------"
},
{
"path": "apiary.apib",
"chars": 82479,
"preview": "emFORMAT: 1A\nHOST: http://r3bfish.ddns.net:8083/ZAutomation/api\n\n# Z-Way API\n\n+ Allowed HTTPs requests:\n\t+ POST\t To cre"
},
{
"path": "classes/AuthController.js",
"chars": 9001,
"preview": "/*** Automation Webserver Auth Controller *************************************\n\nVersion:\n------------------------------"
},
{
"path": "classes/AutomationController.js",
"chars": 103938,
"preview": "/*** Z-Way HA Controller class module *****************************************\n\n Version: 1.0.0\n ----------------------"
},
{
"path": "classes/AutomationModule.js",
"chars": 9517,
"preview": "/*** Z-Way HA Automation module base class ************************************\n\nVersion: 1.0.0\n------------------------"
},
{
"path": "classes/DevicesCollection.js",
"chars": 6495,
"preview": "/*** Z-Way DevicesCollection class ************************************\n\n Version: 1.0.0\n ------------------------------"
},
{
"path": "classes/VirtualDevice.js",
"chars": 11691,
"preview": "/*** Z-Way HA Virtual Device base class ***************************************\n\nVersion: 2.0.0\n------------------------"
},
{
"path": "defaultConfigs/README",
"chars": 793,
"preview": "These configs are used to prepare distribs for different platforms\n\nNB! Please keep all theses files beautified! Use htt"
},
{
"path": "defaultConfigs/config.json",
"chars": 7504,
"preview": "{\n\t\"controller\": {\n\t\t\"initial\": true\n\t},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_i"
},
{
"path": "defaultConfigs/config.json_WB",
"chars": 8479,
"preview": "{\n\t\"controller\": {\n\t\t\"initial\": true\n\t},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_i"
},
{
"path": "defaultConfigs/config.json_ttyACM0",
"chars": 7504,
"preview": "{\n\t\"controller\": {\n\t\t\"initial\": true\n\t},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_i"
},
{
"path": "defaultConfigs/config.json_ttyACM0_ZBW-WD",
"chars": 7250,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_ttyACM0_ZBW-no",
"chars": 7080,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_ttyAMA0",
"chars": 7424,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_ttyAMA0_NonExpert",
"chars": 6174,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_ttyS0",
"chars": 7422,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_ttyS0-JBox",
"chars": 6741,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_ttyS0-ReHub",
"chars": 6598,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_ttyS1",
"chars": 7238,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_ttyUSB0_ZBW-no_vDev-no",
"chars": 4574,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "defaultConfigs/config.json_windows",
"chars": 7082,
"preview": "{\n\t\"controller\": {},\n\t\"vdevInfo\": {},\n\t\"locations\": [{\n\t\t\"id\": 0,\n\t\t\"title\": \"globalRoom\",\n\t\t\"user_img\": \"\",\n\t\t\"default_"
},
{
"path": "lang/cn.json",
"chars": 3106,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Depend"
},
{
"path": "lang/cz.json",
"chars": 3129,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Nebyla"
},
{
"path": "lang/de.json",
"chars": 3817,
"preview": "{\n \"ac_err_create_instance\": \"Es konnte keine neue Instanz von der App erzeugt werden. [APP] :: [INSTANZ ID] = \",\n "
},
{
"path": "lang/en.json",
"chars": 3106,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Depend"
},
{
"path": "lang/es.json",
"chars": 3599,
"preview": "{\n \"ac_err_create_instance\": \"No se ha podido crear la instancia. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_fou"
},
{
"path": "lang/fi.json",
"chars": 3106,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Depend"
},
{
"path": "lang/fr.json",
"chars": 3523,
"preview": "{\n \"ac_err_create_instance\": \"Création d'une instance impossible. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_fou"
},
{
"path": "lang/it.json",
"chars": 3106,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Depend"
},
{
"path": "lang/pt.json",
"chars": 3106,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Depend"
},
{
"path": "lang/ru.json",
"chars": 3106,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Depend"
},
{
"path": "lang/se.json",
"chars": 2742,
"preview": "{\t\n\t\"ac_warn_restart\":\"Automationskontrollern är omstartad.\",\n\t\"ac_err_init_module_not_found\":\"Cannot instantiate module"
},
{
"path": "lang/sk.json",
"chars": 3169,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Nebola"
},
{
"path": "lang/sv.json",
"chars": 3106,
"preview": "{\n \"ac_err_create_instance\": \"Cannot create instance. [APP] :: [INSTANCE ID] = \",\n \"ac_err_dep_not_found\": \"Depend"
},
{
"path": "lib/BAOS_API_2011_01_29_001.js",
"chars": 22103,
"preview": "// BAOS_API_2011_01_29_001\nfunction BaosLib()\n{\n\t//////////////////////////////////////////////////\n\t// Member variables"
},
{
"path": "lib/IntelHex2bin.js",
"chars": 2255,
"preview": "// Converts IntelHex into binary 128 kB file\nfunction IntelHex2bin(hex) {\n\tfunction hex2dec(digits) {\n\t\treturn parseInt("
},
{
"path": "lib/LimitedArray.js",
"chars": 1520,
"preview": "/*\n * This class creates an object that can be called to save data stored in object using a saver function.\n * The objec"
},
{
"path": "lib/base64.js",
"chars": 1663,
"preview": "// Public domain version of Base64 encoder/decoder found somewhere in the Internet\n\nvar Base64 = {\n _keyStr:\"ABCDEFGH"
},
{
"path": "lib/eventemitter2.js",
"chars": 19974,
"preview": "/*! EventEmitter2 https://github.com/hij1nx/EventEmitter2 Copyright (c) 2013 hij1nx Licensed under the MIT license.*/\n;!"
},
{
"path": "lib/underscore-umd-min.js",
"chars": 19526,
"preview": "!function(n,r){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=r():\"function\"==typeof define&&define"
},
{
"path": "lib/underscore.js",
"chars": 52915,
"preview": "// Underscore.js 1.8.3\n// http://underscorejs.org\n// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Invest"
},
{
"path": "main.js",
"chars": 7334,
"preview": "/*** Z-Way Home Automation Engine main executable *****************************\n\nVersion: 0.1.2\n(c) ZWave.Me, 2013\n\n----"
},
{
"path": "modules/Alexa/index.js",
"chars": 44320,
"preview": "/*** Alexa Z-Way HA module *******************************************\n\n Version: 1.1.0\n (c) Z-Wave.Me, 2016\n ----------"
},
{
"path": "modules/Alexa/lang/de.json",
"chars": 885,
"preview": "{\n \"m_title\":\"Alexa\",\n \"m_descr\":\"Mit dieser App können Sie ihre SmartHome Geräte und Szenen mit Amazons Echo oder Dot"
},
{
"path": "modules/Alexa/lang/en.json",
"chars": 842,
"preview": "{\n \"m_title\":\"Alexa\",\n \"m_descr\":\"Gives possibility to control your SmartHome devcies and scene with your voice using "
},
{
"path": "modules/Alexa/module.json",
"chars": 509,
"preview": "{\n \"dependencies\": [],\n \"singleton\": true,\n \"category\": \"support_external_dev\",\n \"author\": \"Z-Wave.Me\",\n \"homepage\""
},
{
"path": "modules/Alexa/patchnotes.txt",
"chars": 413,
"preview": "v1.0.3\n- improve error handling\n- add device typ switchRGBW to support RGB bulbs (change color)\nv1.0.2\n- add device typ"
},
{
"path": "modules/AutoLock/index.js",
"chars": 2749,
"preview": "/*** AutoLock Z-Way Home Automation module *************************************\n\n Version: 1.2\n (c) Z-Wave.Me, 2017\n\n -"
},
{
"path": "modules/AutoLock/lang/de.json",
"chars": 968,
"preview": "{\n\t\"m_title\":\"Automatisches Schließen einer Tür\",\n\t\"m_descr\":\"Elektronische Türschlösser treiben zumeist Riegelschaltkon"
},
{
"path": "modules/AutoLock/lang/en.json",
"chars": 848,
"preview": "{\n\t\"m_title\":\"Automated Locking of Door\",\n\t\"m_descr\":\"Electronic Doors typically move the dead bold of the door. If the "
},
{
"path": "modules/AutoLock/lang/ru.json",
"chars": 309,
"preview": "{\n\t\"m_title\":\"Авто закрытие\",\n\t\"m_descr\":\"Датчик открытия двери автоматически закрывает замок при закрытии двери.\",\n\t\"l_"
},
{
"path": "modules/AutoLock/module.json",
"chars": 1735,
"preview": "{\n\t\"dependencies\": [],\n\t\"singleton\": false,\n\t\"category\": \"device_enhancements\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"ht"
},
{
"path": "modules/AutoOff/index.js",
"chars": 3189,
"preview": "/*** AutoOff Z-Way Home Automation module *************************************\n\n Version: 1.0.3\n (c) Z-Wave.Me, 2019\n\n "
},
{
"path": "modules/AutoOff/lang/de.json",
"chars": 752,
"preview": "{\n\t\"m_title\":\"Automatisiertes Ausschalten\",\n\t\"m_descr\":\"Diese App schaltet ein ausgewähltes Gerät (Schalter, Dimmer, Mot"
},
{
"path": "modules/AutoOff/lang/en.json",
"chars": 680,
"preview": "{\n\t\"m_title\":\"Automated Switch Off\",\n\t\"m_descr\":\"This app will automatically turn off a selected device (switch, dimmer,"
},
{
"path": "modules/AutoOff/lang/ru.json",
"chars": 375,
"preview": "{\n\t\"m_title\":\"Авто выключение\",\n\t\"m_descr\":\"Автоматическое выключение устройства через определенное время.\",\n\t\"l_dev\":\"У"
},
{
"path": "modules/AutoOff/module.json",
"chars": 1370,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"device_enhancements\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"ht"
},
{
"path": "modules/BatteryPolling/index.js",
"chars": 4286,
"preview": "/*** BatteryPolling Z-Way HA module *******************************************\n\nVersion: 2.3.0\n(c) Z-Wave.Me, 2020\n----"
},
{
"path": "modules/BatteryPolling/lang/de.json",
"chars": 783,
"preview": "{\n\t\"m_title\":\"Batteriestatus\",\n\t\"m_descr\":\"Die Batteriestandabfrage aktualisiert den Batteriestatus durch wöchentliche A"
},
{
"path": "modules/BatteryPolling/lang/en.json",
"chars": 624,
"preview": "{\n\t\"m_title\":\"Battery Polling\",\n\t\"m_descr\":\"The battery polling will update the battery status by asking all battery-ope"
},
{
"path": "modules/BatteryPolling/lang/ru.json",
"chars": 454,
"preview": "{\n\t\"m_title\":\"Опрос батарей\",\n\t\"m_descr\":\"Оповещение о низком заряде батарей.\",\n\t\"l_launch_wd\":\"Делать опрос заряда бата"
},
{
"path": "modules/BatteryPolling/module.json",
"chars": 1105,
"preview": "{\n\t\"singleton\": true,\n\t\"dependencies\": [\"Cron\"],\n\t\"category\": \"basic_gateway_modules\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepag"
},
{
"path": "modules/BindDevices/index.js",
"chars": 3357,
"preview": "/*** BindDevices Z-Way HA module *******************************************\n\nVersion: 1.0.3\n(c) Z-Wave.Me, 2018\n-------"
},
{
"path": "modules/BindDevices/lang/de.json",
"chars": 321,
"preview": "{\n\t\"m_title\":\"Assoziation\",\n\t\"m_descr\":\"Ein oder mehrere Geräte werden immer DANN geschaltet, WENN ein gewähltes Ereigni"
},
{
"path": "modules/BindDevices/lang/en.json",
"chars": 1353,
"preview": "{\n\t\"m_title\":\"Association\",\n\t\"m_descr\":\"The association is the foundation of automation. A selected action (THEN) is exe"
},
{
"path": "modules/BindDevices/lang/ru.json",
"chars": 172,
"preview": "{\n\t\"m_title\":\"Ассоциации\",\n\t\"m_descr\":\"Прямое ассоциирование устройств друг с другом.\",\n\t\"l_event_sources\":\"Список источ"
},
{
"path": "modules/BindDevices/module.json",
"chars": 2444,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"automation_basic\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
},
{
"path": "modules/Camera/index.js",
"chars": 3609,
"preview": "/*** Camera Z-Way HA module *******************************************\n\nVersion: 1.1.0\n(c) Z-Wave.Me, 2017\n------------"
},
{
"path": "modules/Camera/lang/de.json",
"chars": 786,
"preview": "{\n \"m_title\":\"Web Kamera\",\n \"m_descr\":\"Dieses Modul konfiguriert die eingebundene Kamera und erstellt ein virtuelles G"
},
{
"path": "modules/Camera/lang/en.json",
"chars": 620,
"preview": "{\n\t\"m_title\":\"Web Camera\",\n\t\"m_descr\":\"This module include configuration for a camera and create camera device.\",\n\t\"l_ca"
},
{
"path": "modules/Camera/lang/ru.json",
"chars": 628,
"preview": "{\n\t\"m_title\":\"Web Камера\",\n\t\"m_descr\":\"Этот модуль позволяет настроить управление камерой.\",\n\t\"l_cam_url\":\"URL Камеры\",\n"
},
{
"path": "modules/Camera/module.json",
"chars": 3728,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"surveillance\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http://ra"
},
{
"path": "modules/CloudBackup/Readme.md",
"chars": 0,
"preview": ""
},
{
"path": "modules/CloudBackup/htdocs/js/postRender.js",
"chars": 841,
"preview": "function modulePostRender(control) {\n\tvar scheduler = control.childrenByPropertyId['scheduler'];\n\tvar api = control.data"
},
{
"path": "modules/CloudBackup/index.js",
"chars": 7636,
"preview": "/*** CloudBackup Z-Way HA module *******************************************\n\n Version: 0.1.3 beta\n (c) Z-Wave.Me, 2016\n"
},
{
"path": "modules/CloudBackup/lang/de.json",
"chars": 828,
"preview": "{\n \"m_title\":\"CloudBackup\",\n \"m_descr\":\"Diese App gibt Ihnen die Möglichkeit, Ihre Backups auf dem Remote-Server hochz"
},
{
"path": "modules/CloudBackup/lang/en.json",
"chars": 697,
"preview": "{\n \"m_title\":\"CloudBackup\",\n \"m_descr\":\"Gives possibility to upload and store your backups on the remote server.\",\n \""
},
{
"path": "modules/CloudBackup/module.json",
"chars": 3271,
"preview": "{\n \"dependencies\": [\n\t\"Cron\"\n ],\n \"singleton\": true,\n \"autoload\": true,\n \"category\": \"\",\n \"author\": \"Z-Wave.Me\",\n "
},
{
"path": "modules/CodeDevice/index.js",
"chars": 4487,
"preview": "/*** CodeDevice Z-Way HA module *******************************************\n\nVersion: 1.1.0\n(c) Z-Wave.Me, 2017\n--------"
},
{
"path": "modules/CodeDevice/lang/de.json",
"chars": 2478,
"preview": "{\n\t\"m_title\":\"Virtuelle Gerät (JavaScript)\",\n\t\"m_descr\":\"Die Anwendung dieser App erfordert solide Kenntnisse in der Jav"
},
{
"path": "modules/CodeDevice/lang/en.json",
"chars": 2363,
"preview": "{\n\t\"m_title\":\"Virtual Device (JavaScript)\",\n\t\"m_descr\":\"The use of this app requires solid knowledge of JavaScript progr"
},
{
"path": "modules/CodeDevice/lang/ru.json",
"chars": 2465,
"preview": "{\n\t\"m_title\":\"Виртуальное устройство (JavaScript)\",\n\t\"m_descr\":\"Использование этого приложения требует базовых знаний пр"
},
{
"path": "modules/CodeDevice/module.json",
"chars": 6922,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"developers_stuff\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
},
{
"path": "modules/CorrectValue/index.js",
"chars": 3481,
"preview": "/*** CorrectValue Z-Way Home Automation module *************************************\n\n Version: 1.0.0\n (c) Z-Wave.Me, 20"
},
{
"path": "modules/CorrectValue/lang/de.json",
"chars": 250,
"preview": "{\n\t\"m_title\":\"Correct sensor value\",\n\t\"m_descr\":\"If sensor show not real value, you can correct it\",\n\t\"l_dev\":\"Sensor\",\n"
},
{
"path": "modules/CorrectValue/lang/en.json",
"chars": 250,
"preview": "{\n\t\"m_title\":\"Correct sensor value\",\n\t\"m_descr\":\"If sensor show not real value, you can correct it\",\n\t\"l_dev\":\"Sensor\",\n"
},
{
"path": "modules/CorrectValue/lang/ru.json",
"chars": 310,
"preview": "{\n\t\"m_title\":\"Корректировка значения датчика\",\n\t\"m_descr\":\"Если датчик отображает не точное значение, то можно задать зн"
},
{
"path": "modules/CorrectValue/module.json",
"chars": 1242,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"device_enhancements\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"ht"
},
{
"path": "modules/CounterTriggeringSensor/index.js",
"chars": 2719,
"preview": "/*** Counter triggering binary sensor Z-Way HA module *******************************************\n\nVersion: 1.1.0\n(c) Z-"
},
{
"path": "modules/CounterTriggeringSensor/lang/de.json",
"chars": 364,
"preview": "{\n\t\"m_title\":\"Counter triggering binary sensor\",\n\t\"m_descr\":\"The module considers how many times have triggered the sens"
},
{
"path": "modules/CounterTriggeringSensor/lang/en.json",
"chars": 363,
"preview": "{\n\t\"m_title\":\"Counter triggering binary sensor\",\n\t\"m_descr\":\"The module considers how many times have triggered the sens"
},
{
"path": "modules/CounterTriggeringSensor/lang/ru.json",
"chars": 380,
"preview": "{\n\t\"m_title\":\"Счетчик срабатывания бинарного датчика\",\n\t\"m_descr\":\"Модуль считает сколько раз сработал датчик. Используе"
},
{
"path": "modules/CounterTriggeringSensor/module.json",
"chars": 1685,
"preview": "{\n\t\"dependencies\": [],\n\t\"singleton\": false,\n\t\"category\": \"automation_basic\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
},
{
"path": "modules/Cron/index.js",
"chars": 5200,
"preview": "/*** Cron ZAutomation module **************************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 2013\n----"
},
{
"path": "modules/Cron/lang/de.json",
"chars": 300,
"preview": "{\n\t\"m_title\":\"Systemuhr (CRON)\",\n\t\"m_descr\":\"Diese App generiert die ganze Zeit gesteuerte Ereignisse und sollte aus die"
},
{
"path": "modules/Cron/lang/en.json",
"chars": 287,
"preview": "{\n\t\"m_title\":\"System Clock (CRON)\",\n\t\"m_descr\":\"This app generates all time driven events and should therefore be active"
},
{
"path": "modules/Cron/lang/ru.json",
"chars": 85,
"preview": "{\n\t\"m_title\":\"Cron планировщик\",\n\t\"m_descr\":\"Планировщик используют другие модули.\"\n}"
},
{
"path": "modules/Cron/module.json",
"chars": 465,
"preview": "{\n\t\"singleton\": true,\n\t\"dependencies\": [],\n\t\"category\": \"basic_gateway_modules\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"h"
},
{
"path": "modules/CustomUserCode/index.js",
"chars": 1734,
"preview": " /*** CustomUserCode ZAutomation module ****************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 2013\n\n-"
},
{
"path": "modules/CustomUserCode/lang/de.json",
"chars": 498,
"preview": "{\n\t\"m_title\":\"Benutzer JavaScript Code\",\n\t\"m_descr\":\"Die Anwendung dieser App erfordert solide Kenntnisse in der JavaScr"
},
{
"path": "modules/CustomUserCode/lang/en.json",
"chars": 425,
"preview": "{\n\t\"m_title\":\"Load custom JavaScript code\",\n\t\"m_descr\":\"The use of this app requires solid knowledge of JavaScript progr"
},
{
"path": "modules/CustomUserCode/lang/ru.json",
"chars": 236,
"preview": "{\n\t\"m_title\":\"Пользовательский JavaScript код\",\n\t\"m_descr\":\"Позволяет загружать пользовательский JavaScript код после за"
},
{
"path": "modules/CustomUserCode/module.json",
"chars": 714,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"developers_stuff\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
},
{
"path": "modules/CustomUserCodeLoader/index.js",
"chars": 1718,
"preview": " /*** CustomUserCodeLoader ZAutomation module ****************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 2"
},
{
"path": "modules/CustomUserCodeLoader/lang/de.json",
"chars": 621,
"preview": "{\n\t\"m_title\":\"Lade JavaScript-Dateien von Benutzer\",\n\t\"m_descr\":\"Die Anwendung dieser App erfordert solide Kenntnisse in"
},
{
"path": "modules/CustomUserCodeLoader/lang/en.json",
"chars": 515,
"preview": "{\n\t\"m_title\":\"Load custom JavaScript file\",\n\t\"m_descr\":\"The use of this app requires solid knowledge of JavaScript progr"
},
{
"path": "modules/CustomUserCodeLoader/lang/ru.json",
"chars": 346,
"preview": "{\n\t\"m_title\":\"Пользовательский JavaScript файл\",\n\t\"m_descr\":\"Позволяет загружать пользовательские JavaScript файлы из па"
},
{
"path": "modules/CustomUserCodeLoader/module.json",
"chars": 779,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"developers_stuff\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
},
{
"path": "modules/CustomUserCodeZWay/index.js",
"chars": 2795,
"preview": " /*** CustomUserCodeZWay ZAutomation module ****************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 201"
},
{
"path": "modules/CustomUserCodeZWay/lang/de.json",
"chars": 735,
"preview": "{\n\t\"m_title\":\"Benutzer JavaScript Code für Z-Wave Applikation\",\n\t\"m_descr\":\"Die Anwendung dieser App erfordert solide Ke"
},
{
"path": "modules/CustomUserCodeZWay/lang/en.json",
"chars": 670,
"preview": "{\n\t\"m_title\":\"Load custom JavaScript code for Z-Wave application\",\n\t\"m_descr\":\"The use of this app requires solid knowle"
},
{
"path": "modules/CustomUserCodeZWay/lang/ru.json",
"chars": 498,
"preview": "{\n\t\"m_title\":\"Пользовательский JavaScript код для приложения Z-Wave\",\n\t\"m_descr\":\"Позволяет загружать пользовательский J"
},
{
"path": "modules/CustomUserCodeZWay/module.json",
"chars": 1272,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"developers_stuff\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
},
{
"path": "modules/DecomposeRGB/index.js",
"chars": 3950,
"preview": "/*** DecomposeRGB Z-Way HA module *******************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 2021\n------"
},
{
"path": "modules/DecomposeRGB/lang/en.json",
"chars": 159,
"preview": "{\n\t\"m_title\":\"Decompose RGB on dimmers\",\n\t\"m_descr\":\"Decompose RGB on three different dimmers to control them individual"
},
{
"path": "modules/DecomposeRGB/lang/ru.json",
"chars": 171,
"preview": "{\n\t\"m_title\":\"Разложение RGB на диммеры\",\n\t\"m_descr\":\"Раскладывает RGB устройство на три диммера для индивидуального упр"
},
{
"path": "modules/DecomposeRGB/module.json",
"chars": 886,
"preview": "{\n\t\"dependencies\": [],\n\t\"singleton\": false,\n\t\"category\": \"legacy_products_workaround\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepag"
},
{
"path": "modules/DelayedScene/index.js",
"chars": 2537,
"preview": "/*** DelayedScene Z-Way HA module *******************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 2014\n------"
},
{
"path": "modules/DelayedScene/lang/de.json",
"chars": 844,
"preview": "{\n\t\"m_title\":\"Verzögerte Aktion\",\n\t\"m_descr\":\"Diese App kann nach einer gewissen Verzögerungszeit auf eine bereits ausge"
},
{
"path": "modules/DelayedScene/lang/en.json",
"chars": 708,
"preview": "{\n\t\"m_title\":\"Delayed Action\",\n\t\"m_descr\":\"This app can trigger one scene after a defined delay after another scene was "
},
{
"path": "modules/DelayedScene/lang/ru.json",
"chars": 300,
"preview": "{\n\t\"m_title\":\"Отложенная сцена\",\n\t\"m_descr\":\"Запуск сцен с задержкой.\",\n\t\"r_l_options\":\"Перезапустить таймер при срабаты"
},
{
"path": "modules/DelayedScene/module.json",
"chars": 1586,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"automation_basic\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
},
{
"path": "modules/DeviceHistory/index.js",
"chars": 11707,
"preview": "/*** DeviceHistory Z-Way HA module *******************************************\n\n Version: 2.0.0\n (c) Z-Wave.Me, 2015\n --"
},
{
"path": "modules/DeviceHistory/lang/de.json",
"chars": 1684,
"preview": "{\n\t\"m_title\":\"24 Stunden Gerätehistorie\",\n\t\"m_descr\":\"Diese App fügt jedem Sensor und Aktor ein kleines Icon bei. Klickt"
},
{
"path": "modules/DeviceHistory/lang/en.json",
"chars": 1417,
"preview": "{\n\t\"m_title\":\"24 Hours Device History\",\n\t\"m_descr\":\"This app adds a little icon to every sensor and actor. Clicking on t"
},
{
"path": "modules/DeviceHistory/module.json",
"chars": 1042,
"preview": "{\n\t\"singleton\" : true,\n\t\"dependencies\": [\"Cron\"],\n\t\"category\" : \"device_enhancements\",\n\t\"author\" : \"Z-Wave.Me\",\n\t\"homepa"
},
{
"path": "modules/DeviceHistory/patchnotes.txt",
"chars": 499,
"preview": "v1.3.0\n- remove support of virtual devices with binary states, because SHUI view has changed and makes it unecessary\n- m"
},
{
"path": "modules/DummyDevice/index.js",
"chars": 3418,
"preview": "/*** DummyDevice Z-Way HA module *******************************************\n\nVersion: 1.2.0\n(c) Z-Wave.Me, 2022\n-------"
},
{
"path": "modules/DummyDevice/lang/de.json",
"chars": 509,
"preview": "{\n\t\"m_title\":\"Gerätattrappe\",\n\t\"m_descr\":\"Wie der Name verrät, erstellt diese App ein virtuelles Gerät, welches nur auf "
},
{
"path": "modules/DummyDevice/lang/en.json",
"chars": 440,
"preview": "{\n\t\"m_title\":\"Dummy Device\",\n\t\"m_descr\":\"As the name suggests this app creates a virtual device that just exists on the "
},
{
"path": "modules/DummyDevice/lang/ru.json",
"chars": 201,
"preview": "{\n\t\"m_title\":\"Устройство пустышка\",\n\t\"m_descr\":\"Устройство пустышку можно использовать например, как флаг, обозначающий "
},
{
"path": "modules/DummyDevice/module.json",
"chars": 967,
"preview": "{\n\t\"singleton\" : false,\n\t\"dependencies\": [],\n\t\"category\": \"automation_basic\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http"
},
{
"path": "modules/EasyScripting/htdocs/js/compile.sh",
"chars": 640,
"preview": "#!/bin/bash\n\ncompileJS() {\n\tlocal IFILE=$1\n\tlocal OFILE=$2\n\tlocal OPT_LEVEL=$3\n\tURL=$(wget -q https://closure-compiler.a"
},
{
"path": "modules/EasyScripting/htdocs/js/postRender-with-comments.js",
"chars": 13709,
"preview": "function modulePostRender(control) {\n\t// advanced code editor is available only on Chome\n\tif (!window.chrome) {\n\t\t$(\".al"
},
{
"path": "modules/EasyScripting/htdocs/js/postRender.js",
"chars": 7089,
"preview": "function modulePostRender(C){function y(a,b,c){var e=null!=window.mozInnerScreenX;c=document.createElement(\"div\");c.id=\""
},
{
"path": "modules/EasyScripting/index.js",
"chars": 5169,
"preview": "/*** EasyScripting Z-Way HA module *******************************************\n\n(c) Z-Wave.Me, 2021\n--------------------"
},
{
"path": "modules/EasyScripting/lang/en.json",
"chars": 3979,
"preview": "{\n\t\"m_title\":\"Easy Scripting\",\n\t\"m_descr\":\"Examples how to easy make automation on JavaScript (ECMA5).<br><br><b>Directi"
},
{
"path": "modules/EasyScripting/lang/ru.json",
"chars": 4146,
"preview": "{\n\t\"m_title\":\"Простые Скрипты\",\n\t\"m_descr\":\"Примеры, как просто писать скрипты автоматизации на JavaScript (ECMA5).<br><"
},
{
"path": "modules/EasyScripting/module.json",
"chars": 707,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"developers_stuff\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
},
{
"path": "modules/EdimaxSP1101/index.js",
"chars": 2385,
"preview": "/*** EdimaxSP1101 Z-Way HA module *******************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 2017\n------"
},
{
"path": "modules/EdimaxSP1101/lang/de.json",
"chars": 284,
"preview": "{\n\t\"m_title\":\"Edimax SP-1101\",\n\t\"m_descr\":\"Diese App ermöglicht Ihnen die Steuerung Ihrer Edimax SP-1101 WLAN Steckdose."
},
{
"path": "modules/EdimaxSP1101/lang/en.json",
"chars": 237,
"preview": "{\n\t\"m_title\":\"Edimax SP-1101\",\n\t\"m_descr\":\"This app allows you to control your Edimax SP-1101 WLAN plugs. Simply enter t"
},
{
"path": "modules/EdimaxSP1101/module.json",
"chars": 879,
"preview": "{\n \"singleton\": false,\n \"dependencies\": [],\n \"category\": \"wifiplug\",\n \"author\": \"Z-Wave.Me\",\n \"homepage\":"
},
{
"path": "modules/EdimaxSP2101/index.js",
"chars": 2385,
"preview": "/*** EdimaxSP2101 Z-Way HA module *******************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 2017\n------"
},
{
"path": "modules/EdimaxSP2101/lang/de.json",
"chars": 284,
"preview": "{\n\t\"m_title\":\"Edimax SP-2101\",\n\t\"m_descr\":\"Diese App ermöglicht Ihnen die Steuerung Ihrer Edimax SP-2101 WLAN Steckdose."
},
{
"path": "modules/EdimaxSP2101/lang/en.json",
"chars": 237,
"preview": "{\n\t\"m_title\":\"Edimax SP-2101\",\n\t\"m_descr\":\"This app allows you to control your Edimax SP-2101 WLAN plugs. Simply enter t"
},
{
"path": "modules/EdimaxSP2101/module.json",
"chars": 879,
"preview": "{\n \"singleton\": false,\n \"dependencies\": [],\n \"category\": \"wifiplug\",\n \"author\": \"Z-Wave.Me\",\n \"homepage\":"
},
{
"path": "modules/EnOcean/index.js",
"chars": 26945,
"preview": "/*** EnOcean Binding module ********************************************************\n\nVersion: 1.0.0\n-------------------"
},
{
"path": "modules/EnOcean/lang/de.json",
"chars": 1005,
"preview": "{\n\t\"m_title\":\"EnOcean Netzwerksteuerung\",\n\t\"m_descr\":\"Ermöglicht die Nutzung von EnOcean Geräten, die mit dem Gateway ve"
},
{
"path": "modules/EnOcean/lang/en.json",
"chars": 918,
"preview": "{\n\t\"m_title\":\"EnOcean Network Access\",\n\t\"m_descr\":\"Allows accessing EnOcean devices from attached EnOcean transceiver.\","
},
{
"path": "modules/EnOcean/lang/ru.json",
"chars": 947,
"preview": "{\n\t\"m_title\":\"EnOcean движок\",\n\t\"m_descr\":\"Активация EnOcean движка.\",\n\t\"l_port\":\"Порт для EnOcean платы/стика\",\n\t\"l_nam"
},
{
"path": "modules/EnOcean/module.json",
"chars": 1616,
"preview": "{\n\t\"dependencies\": [],\n\t\"singleton\": true,\n\t\"category\": \"peripherals\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http://razb"
},
{
"path": "modules/FosCam9805/index.js",
"chars": 3429,
"preview": "/*** FosCam9805 Z-Way HA module *******************************************\n\nVersion: 1.1.0\n(c) Z-Wave.Me, 2017\n--------"
},
{
"path": "modules/FosCam9805/lang/de.json",
"chars": 417,
"preview": "{\n\t\"m_descr\":\"Ünterstützung der FosCam Outdoor Kameras (FI9805W,FI8905W,FI9805E)\",\n\t\"ip\":\"Kamera IP-Adresse\",\n\t\"h_ip\":\"B"
},
{
"path": "modules/FosCam9805/lang/en.json",
"chars": 368,
"preview": "{\n\t\"m_descr\":\"Support the FosCam Outdoor Cameras (FI9805W,FI8905W,FI9805E)\",\n\t\"ip\":\"Camera IP URL\",\n\t\"h_ip\":\"in the form"
},
{
"path": "modules/FosCam9805/lang/ru.json",
"chars": 364,
"preview": "{\n\t\"m_descr\":\"Поддержка Уличных Камер FosCam (FI9805W,FI8905W,FI9805E).\",\n\t\"ip\":\"URL Камеры\",\n\t\"h_ip\":\"В формате 'http:/"
},
{
"path": "modules/FosCam9805/module.json",
"chars": 1514,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"surveillance\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http://ww"
},
{
"path": "modules/FosCam9821/index.js",
"chars": 3718,
"preview": "/*** FosCam9821 Z-Way HA module *******************************************\n\nVersion: 1.1.0\n(c) Z-Wave.Me, 2017\n--------"
},
{
"path": "modules/FosCam9821/lang/de.json",
"chars": 425,
"preview": "{\n\t\"m_descr\":\"Ünterstützung der FosCam Indoor Kameras ohne Zoom (FI9821, FI9831, FI8910)\",\n\t\"ip\":\"Kamera IP-Adresse\",\n\t\""
},
{
"path": "modules/FosCam9821/lang/en.json",
"chars": 379,
"preview": "{\n\t\"m_descr\":\"Support the FosCam Indoor Cameras without Zoom (FI9821, FI9831, FI8910)\",\n\t\"ip\":\"Camera IP URL\",\n\t\"h_ip\":\""
},
{
"path": "modules/FosCam9821/lang/ru.json",
"chars": 364,
"preview": "{\n\t\"m_descr\":\"Поддержка Камер FosCam без зума (FI9821, FI9831, FI8910).\",\n\t\"ip\":\"URL Камеры\",\n\t\"h_ip\":\"В формате 'http:/"
},
{
"path": "modules/FosCam9821/module.json",
"chars": 1514,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"surveillance\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http://ww"
},
{
"path": "modules/FosCam9826/index.js",
"chars": 4116,
"preview": "/*** FosCam9826 Z-Way HA module *******************************************\n\nVersion: 1.1.0\n(c) Z-Wave.Me, 2017\n--------"
},
{
"path": "modules/FosCam9826/lang/de.json",
"chars": 398,
"preview": "{\n\t\"m_descr\":\"Ünterstützung der Indoor Zoom Kameras (FI9826W)\",\n\t\"ip\":\"Kamera IP-Adresse\",\n\t\"h_ip\":\"Beispielformat: 'htt"
},
{
"path": "modules/FosCam9826/lang/en.json",
"chars": 356,
"preview": "{\n\t\"m_descr\":\"Support the FosCam Indoor Zoom Cameras (FI9826W)\",\n\t\"ip\":\"Camera IP URL\",\n\t\"h_ip\":\"in the format 'http://I"
},
{
"path": "modules/FosCam9826/lang/ru.json",
"chars": 348,
"preview": "{\n\t\"m_descr\":\"Поддержка Камер FosCam с зумом (FI9826W).\",\n\t\"ip\":\"URL Камеры\",\n\t\"h_ip\":\"В формате 'http://IPADDRESS:PORT'"
},
{
"path": "modules/FosCam9826/module.json",
"chars": 1514,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"surveillance\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http://ww"
},
{
"path": "modules/FosCam9828/index.js",
"chars": 4119,
"preview": "/*** FosCam9828 Z-Way HA module *******************************************\n\nVersion: 1.1.0\n(c) Z-Wave.Me, 2017\n--------"
},
{
"path": "modules/FosCam9828/lang/de.json",
"chars": 413,
"preview": "{\n\t\"m_descr\":\"Ünterstützung der FosCam Dome Outdoor Kameras (FI9828, FI9819)\",\n\t\"ip\":\"Kamera IP-Adresse\",\n\t\"h_ip\":\"Beisp"
},
{
"path": "modules/FosCam9828/lang/en.json",
"chars": 364,
"preview": "{\n\t\"m_descr\":\"Support the FosCam dome Outdoor Cameras (FI9828, FI9819)\",\n\t\"ip\":\"Camera IP URL\",\n\t\"h_ip\":\"in the format '"
},
{
"path": "modules/FosCam9828/lang/ru.json",
"chars": 355,
"preview": "{\n\t\"m_descr\":\"Поддержка Уличных Камер FosCam (FI9828, FI9819).\",\n\t\"ip\":\"URL Камеры\",\n\t\"h_ip\":\"В формате 'http://IPADDRES"
},
{
"path": "modules/FosCam9828/module.json",
"chars": 1514,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"surveillance\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http://ww"
},
{
"path": "modules/GlobalCache/index.js",
"chars": 2160,
"preview": "/*** GlobalCache Z-Way HA module *******************************************\n\nVersion: 1.0.0\n(c) Z-Wave.Me, 2014\n-------"
},
{
"path": "modules/GlobalCache/lang/de.json",
"chars": 760,
"preview": "{\n\t\"m_title\":\"Global Caché\",\n\t\"m_descr\":\"Global Cache ist ein Hersteller verschiedener Geräte, die per IP Befehl an- bzw"
},
{
"path": "modules/GlobalCache/lang/en.json",
"chars": 730,
"preview": "{\n\t\"m_title\":\"Global Caché\",\n\t\"m_descr\":\"Global Cache is a manufacturer of various devices that can be turned on/off usi"
},
{
"path": "modules/GlobalCache/lang/ru.json",
"chars": 309,
"preview": "{\n\t\"m_title\":\"Global Caché\",\n\t\"m_descr\":\"Создать кнопку, отправляющую команду устройству Global Caché.\",\n\t\"l_host\":\"IP и"
},
{
"path": "modules/GlobalCache/module.json",
"chars": 886,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"support_external_dev\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"h"
},
{
"path": "modules/GoogleHome/index.js",
"chars": 6786,
"preview": "/*** GoogleHome Z-Way HA module *******************************************\n\n Version: 0.0.2 beta\n (c) Z-Wave.Me, 2019\n "
},
{
"path": "modules/GoogleHome/lang/de.json",
"chars": 128,
"preview": "{\n \"m_title\":\"Google Home\",\n \"m_descr\":\"Mit diesem Modul können Sie Ihre Z-Way Geräte über den Google-Assistenten steu"
},
{
"path": "modules/GoogleHome/lang/en.json",
"chars": 122,
"preview": "{\n \"m_title\":\"Google Home\",\n \"m_descr\":\"This module let you control your Z-Way devices through the Google Assistant.\"\n"
},
{
"path": "modules/GoogleHome/module.json",
"chars": 452,
"preview": "{\n \"dependencies\": [],\n \"singleton\": true,\n \"category\": \"support_external_dev\",\n \"author\": \"Z-Wave.Me\",\n \"homepage\""
},
{
"path": "modules/GroupDevices/index.js",
"chars": 5167,
"preview": "/*** GroupDevices Z-Way HA module *******************************************\n\nVersion: 2.1.0\n(c) Z-Wave.Me, 2017\n------"
},
{
"path": "modules/GroupDevices/lang/de.json",
"chars": 1521,
"preview": "{\n\t\"m_title\":\"Gerätegruppe\",\n\t\"m_descr\":\"Gruppiert Geräte in einem Element. Das Element kann sowohl ein- und ausgeschalt"
},
{
"path": "modules/GroupDevices/lang/en.json",
"chars": 1248,
"preview": "{\n\t\"m_title\":\"Group devices\",\n\t\"m_descr\":\"Groups devices into one element. The element can either be on/off or even dimm"
},
{
"path": "modules/GroupDevices/lang/ru.json",
"chars": 604,
"preview": "{\n\t\"m_title\":\"Группа устройств\",\n\t\"m_descr\":\"Объединить несколько устройств в одну группу.\",\n\t\"rl_options\":\"Диммируемая "
},
{
"path": "modules/GroupDevices/module.json",
"chars": 2845,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"device_enhancements\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"ht"
},
{
"path": "modules/HTTPDevice/index.js",
"chars": 7461,
"preview": "/*** HTTPDevice Z-Way HA module *******************************************\n\nVersion: 2.2.1\n(c) Z-Wave.Me, 2020\n--------"
},
{
"path": "modules/HTTPDevice/lang/de.json",
"chars": 4588,
"preview": "{\n\t\"m_title\":\"HTTP-Gerät\",\n\t\"m_descr\":\"Die Anwendung dieser App erfordert solide Kenntnisse in der JavaScript Programmie"
},
{
"path": "modules/HTTPDevice/lang/en.json",
"chars": 4135,
"preview": "{\n\t\"m_title\":\"HTTP Device\",\n\t\"m_descr\":\"The use of this app requires solid knowledge of JavaScript programming. This app"
},
{
"path": "modules/HTTPDevice/lang/ru.json",
"chars": 3016,
"preview": "{\n\t\"m_title\":\"HTTP устройство\",\n\t\"m_descr\":\"Создание устройства основанного на HTTP запросах.\",\n\t\"l_schema\":\"Выберите ти"
},
{
"path": "modules/HTTPDevice/module.json",
"chars": 9999,
"preview": "{\n\t\"singleton\": false,\n\t\"dependencies\": [],\n\t\"category\": \"developers_stuff\",\n\t\"author\": \"Z-Wave.Me\",\n\t\"homepage\": \"http:"
}
]
// ... and 254 more files (download for full content)
About this extraction
This page contains the full source code of the Z-Wave-Me/home-automation GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 454 files (3.1 MB), approximately 844.7k tokens, and a symbol index with 307 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.