diff --git a/CHANGELOG.md b/CHANGELOG.md index 6df4a793..a4ab30e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,19 @@ # node-red-contrib-zwave-js Change Log + + - 3.5.0 **Possible Breaking Change** + - Added support for **User Code** CC to Managed mode + - Added support for **Alarm Sensor** CC to Managed mode + - Added support for **Barrier Operator** CC to Managed mode + - Added support for **Clock** CC to Managed mode + - Fixed Meter Optional param + - Removed a temporary work around capturing the mismatched **endPoint** property + **endpoint** is now the required property (no longer a capital P) if specifying the endpoint. + See change log for **1.3.0**. + - Optimisations to **Duration** porcessing + - The **forceUpdate** object for Managed access, can now contain any property normally found in the ValueID interface. + Including overwriting the **endpoint** property - which will normally be provided for you. + - Bump Z-Wave JS to 7.5.2 + - Bump Serial Ports - 3.4.0 **Deprecation Warnings** - Added a **PollValue** method to the Unmanaged class diff --git a/README.md b/README.md index f33a8da1..e701888f 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,14 @@ # node-red-contrib-zwave-js An extremely easy to use, zero dependency and feature rich Z-Wave node for Node Red, based on Z-Wave JS. The implementation is 100% javascript. it is therefore: - - Very fast + - Extremely fast - Does not require a build of any static library - Stable Install this node via the Node Red palette menu (See [Home Assistant Install](#home-assistant-install) if this applies to you), and you have Z-Wave support in Node Red. - + +It offers a massive amount of flexibility and is packed full of features. The node is straightforward to use, and removes all the complexities that you would otherwise need to deal with. - Add the node into your flow @@ -25,8 +26,8 @@ The node is straightforward to use, and removes all the complexities that you wo Z-Wave JS is actively maintained, fast and supports the security command class. ## Home Assistant Install -Please note: This is a self contained Z-Wave driver for Node Red, it will not work along side the Z-Wave plugin for Home Assistant. -if this isn't your setup, then please refer to the below guide to install into the Node Red instance that HA provides. +Please note: This is a self contained Z-Wave driver for Node Red, it will not work along side the Z-Wave add-on for Home Assistant. +If however, you use the Node Red add-on, and want Z-Wave to be managed from with-in Node Red, see below for instructions. - Do not attempt to install this node, via the palette menu - it will likely not install some serial port stuff. - Edit the Node Red add-on configuration as below (specifically **system_packages** and **npm_packages**) @@ -48,7 +49,8 @@ npm_packages: ## Node config (Advanced Driver Settings) **Custom CFG Dir** Z-Wave JS allows a custom directory, that will be used to search for additonal Device configuration files. -Note: if an internal device config is found to have the same identifiers, the one in the custom folder will take priority. +Note: if an internal device config is found to have the same identifiers, the one in the directory folder will take priority. +Please also note, the specified directory will be recursively scanned. **Disk IO Throttle** If using **Unmanaged** Mode (see further down), the values received from **GetValue**, will be from a cache. @@ -189,14 +191,14 @@ let Message = { return Message; ``` -## Notes on StartInclusion +## Notes on Controller -> StartInclusion By default, the include process will only include secure devices, if you want to include non-secure devices, provide a **true** value -## Notes on HardReset +## Notes on Controller -> HardReset A one-way ticket for wiping out all the configuration on the controller. Once you call this method, there is no going back - you are hearby **WARNED of the consequences**. -## Notes on ProprietaryFunc +## Notes on Controller -> ProprietaryFunc The **Data** argument, must ONLY contain the data portion of the request As an example, this byte array **[0x01, 0x08, 0x00, 0xF2, 0x51, 0x01, 0x00, 0x05, 0x01, 0x51]** disables the LED on the GEN 5 Z-Stick, breaking it down we have: diff --git a/managed.md b/managed.md index 3e278dbf..889de78c 100644 --- a/managed.md +++ b/managed.md @@ -27,12 +27,21 @@ Currently, the supported command classes are (when using Managed mode). | Association (Deprecated) | RemoveNodesFromAllGroups | [NodeIDs: Number[]] | | Association (Deprecated) | GetGroupCount | | | AssociationGroupInfo (Deprecated) | GetGroupName | [Group ID: Number] | +| AlarmSensor | Get | [**AlarmSensorType**: Enum (Optional)] | +| AlarmSensor | GetSupportedSensorTypes | | +| BarrierOperator | Set | [**BarrierState**: Enum] | +| BarrierOperator | Get | | +| BarrierOperator | GetSignalingCapabilities | | +| BarrierOperator | GetEventSignaling | [**SubsystemType**: Enum] | +| BarrierOperator | SetEventSignaling | [**SubsystemType**: Enum, **SubsystemState**: Enum] | | Basic | Set | [Number] | | Basic | Get | | | Battery | Get | | | BinarySensor | Get | [**BinarySensorType**: Enum] | | BinarySwitch | Set | [Bool, **Duration**: Object (Optional)] | | BinarySwitch | Get | | +| Clock | Set | [Hour: Number, Minute: Number, **Weekday**: Enum (Optional)] | +| Clock | Get | | | Configuration | Set | [ParamID: Number, Value: Number, Value Length: Number]| | Configuration | Get | [ParamID: Number] | | ColorSwitch | Set | [**Color**: Object] | @@ -46,7 +55,7 @@ Currently, the supported command classes are (when using Managed mode). | Lock | Get | | | Indicator | Set | [Value: Number] \| [**Indicator**[]: Object] | | Indicator | Get | [Indicator: Number (Optional)] | -| Meter | Get | [**MeterOptions**: Object] | +| Meter | Get | [**MeterOptions**: Object (Optional)] | | Meter | GetAll | | | Meter | Reset | [**MeterResetOptions**: Object] | | MultiLevelSwitch | Set | [Number, **Duration**: Object (Optional)] | @@ -67,8 +76,16 @@ Currently, the supported command classes are (when using Managed mode). | ThermostatSetPoint | Set | [**SetPointType**: Enum, Value: Number, Scale: Number] | | ThermostatSetPoint | Get | [**SetPointType**: Enum] | | ThermostatOperatingState | Get | | -| ThermostatSetback | Set (See Notes) | [**SetbackType**: Enum, Set Back State: String \| Number] | +| ThermostatSetback | Set (See Notes) | [**SetbackType**: Enum, Set Back State: String \| Number] | | ThermostatSetback | Get | | +| UserCode | Set | [UserID: Number, **UserIDStatus**: Enum, UserCode: String] | +| UserCode | GetUsersCount | | +| UserCode | Get | [UserID: Number, Multiple: Bool (Optional)] | +| UserCode | Clear (see notes) | [UserID: Number] | +| UserCode | GetKeypadMode | | +| UserCode | SetKeypadMode | [**KeypadMode**: Enum] | +| UserCode | GetMasterCode | | +| UserCode | SetMasterCode | [Code: String] | | WakeInterval | Set (See Notes) | [Seconds: Number, Controller Node ID:Number] | | WakeInterval | Get | | @@ -142,9 +159,12 @@ return Message ``` ## Forcing Updates -If you prefer Managed Mode, but have devices (or endpoints), that do not report back updated values, +If you prefer Managed Mode, but have devices (or endpoints), that do not report back updated values, you can enforce an update by suppplying a **forceUpdate** object, and providing -a **property** and optionally **propertyKey** - both of which are avalable in VALUE_UPDATED events. +properties normally found in **VALUE_UPDATED** events, namely **property** and sometimes **propertyKey**. + +Whilst you can overwrite the force update request and set **endpoint** and **commandClass**, +Unless there is a specific reason to do so, it's best to allow the system to take care of this for you. This will cause extra traffic in your network, so only use this if needed. @@ -175,15 +195,17 @@ Please see the [🔗Associations](./README.md#controllerdriver-and-associat - RemoveAssociations - RemoveNodeFromAllAssociations +## Notes on UserCode -> Clear +Specifying 0, will clear all User Codes. -## Notes on WakeInterval +## Notes on WakeInterval -> Set When setting the interval, the **Controller Node ID** parameter will almost certainly be 1 - unless you have multiple controllers, and you want the wake up to be recieved by a different controller. -## Notes on GetSupportedKeys +## Notes on EntryControl -> GetSupportedKeys This will return an array of ASCII codes - representing the keys that are supported on the device -## Notes on ThermostatSetback +## Notes on ThermostatSetback -> Set If specifing a string, the valid values are: **Frost Protection** | **Energy Saving** | **Unused** ## Object Structures diff --git a/package.json b/package.json index 6a286686..ab5d16ec 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "node-red-contrib-zwave-js", - "version": "3.4.0", + "version": "3.5.0", "license": "MIT", "description": "An extremely easy to use, zero dependency and feature rich Z-Wave node for Node Red, based on Z-Wave JS.", "dependencies": { - "serialport": "9.0.7", - "zwave-js": "7.4.0", + "serialport": "9.0.8", + "zwave-js": "7.5.2", "winston": "3.3.3" }, "keywords": [ diff --git a/zwave-js/FunctionMaps.json b/zwave-js/FunctionMaps.json index daae52a9..4852dda1 100644 --- a/zwave-js/FunctionMaps.json +++ b/zwave-js/FunctionMaps.json @@ -1,4 +1,131 @@ { + "Clock": { + "MapsToClass": "Clock", + "Operations": { + "Get": { + "MapsToFunc": "get", + "ParamsOptional": 0, + "ParamsRequired": 0 + }, + "Set": { + "MapsToFunc": "set", + "ParamsOptional": 1, + "ParamsRequired": 2, + "ParamEnumDependency": { + "2": "Weekday" + } + } + } + }, + "UserCode": { + "MapsToClass": "User Code", + "Operations": { + "GetUsersCount": { + "MapsToFunc": "getUsersCount", + "ParamsOptional": 0, + "ParamsRequired": 0 + }, + "Get": { + "MapsToFunc": "get", + "ParamsOptional": 1, + "ParamsRequired": 1 + }, + "Set": { + "MapsToFunc": "set", + "ParamsOptional": 0, + "ParamsRequired": 3, + "ParamEnumDependency": { + "1": "UserIDStatus" + } + }, + "Clear": { + "MapsToFunc": "clear", + "ParamsOptional": 0, + "ParamsRequired": 1 + }, + "GetKeypadMode": { + "MapsToFunc": "getKeypadMode", + "ParamsOptional": 0, + "ParamsRequired": 0 + }, + "SetKeypadMode": { + "MapsToFunc": "setKeypadMode", + "ParamsOptional": 0, + "ParamsRequired": 1, + "ParamEnumDependency": { + "0": "KeypadMode" + } + }, + "GetMasterCode": { + "MapsToFunc": "getMasterCode", + "ParamsOptional": 0, + "ParamsRequired": 0 + }, + "SetMasterCode": { + "MapsToFunc": "setMasterCode", + "ParamsOptional": 0, + "ParamsRequired": 1 + } + } + }, + "AlarmSensor": { + "MapsToClass": "Alarm Sensor", + "Operations": { + "Get": { + "MapsToFunc": "get", + "ParamsOptional": 1, + "ParamsRequired": 0, + "ParamEnumDependency": { + "0": "AlarmSensorType" + } + }, + "GetSupportedSensorTypes": { + "MapsToFunc": "getSupportedSensorTypes", + "ParamsOptional": 0, + "ParamsRequired": 0 + } + } + }, + "BarrierOperator": { + "MapsToClass": "Barrier Operator", + "Operations": { + "Get": { + "MapsToFunc": "get", + "ParamsOptional": 0, + "ParamsRequired": 0 + }, + "Set": { + "MapsToFunc": "set", + "ParamsOptional": 0, + "ParamsRequired": 1, + "ParamEnumDependency": { + "0": "BarrierState" + } + }, + "GetSignalingCapabilities": { + "MapsToFunc": "getSignalingCapabilities", + "ParamsOptional": 0, + "ParamsRequired": 0 + }, + "GetEventSignaling": { + "MapsToFunc": "getEventSignaling", + "ParamsOptional": 1, + "ParamsRequired": 0, + "ParamEnumDependency": { + "0": "SubsystemType" + } + }, + "SetEventSignaling": { + "MapsToFunc": "setEventSignaling", + "ParamsOptional": 0, + "ParamsRequired": 2, + "ParamEnumDependency": { + "0": "SubsystemType", + "1": "SubsystemState" + } + } + } + }, "MultilevelSensor": { "MapsToClass": "Multilevel Sensor", "Operations": { @@ -85,8 +212,8 @@ "Operations": { "Get": { "MapsToFunc": "get", - "ParamsRequired": 1, - "ParamsOptional": 0 + "ParamsRequired": 0, + "ParamsOptional": 1 }, "GetAll": { "MapsToFunc": "getAll", diff --git a/zwave-js/zwave-js.js b/zwave-js/zwave-js.js index bc3a4b77..cf77af5d 100644 --- a/zwave-js/zwave-js.js +++ b/zwave-js/zwave-js.js @@ -21,6 +21,13 @@ module.exports = function (RED) { ThermostatMode: ZWaveJS.ThermostatMode, SetPointType: ZWaveJS.ThermostatSetpointType, DoorLockMode: ZWaveJS.DoorLockMode, + AlarmSensorType: ZWaveJS.AlarmSensorType, + BarrierState:ZWaveJS.BarrierState, + SubsystemType:ZWaveJS.SubsystemType, + SubsystemState:ZWaveJS.SubsystemState, + UserIDStatus:ZWaveJS.UserIDStatus, + KeypadMode:ZWaveJS.KeypadMode, + Weekday:ZWaveJS.Weekday, // node enums InterviewStage: ZWaveJS.InterviewStage, @@ -520,8 +527,6 @@ module.exports = function (RED) { if (msg.payload.hasOwnProperty("endpoint")) { EP = parseInt(msg.payload.endpoint) - } else if (msg.payload.hasOwnProperty("endPoint")) { - EP = parseInt(msg.payload.endPoint) } if (Func.hasOwnProperty("ParamEnumDependency")) { @@ -559,13 +564,12 @@ module.exports = function (RED) { if(forceUpdate !== undefined){ let VID = { - commandClass:Map.MapsToClass, - endpoint:EP, - property:forceUpdate.property, - } - if(forceUpdate.propertyKey !== undefined){ - VID.propertyKey = forceUpdate.propertyKey + commandClass:CommandClasses[Map.MapsToClass], + endpoint:EP } + Object.keys(forceUpdate).forEach((VIDK) =>{ + VID[VIDK] = forceUpdate[VIDK] + }) Log("debug", "REDCTL", "OUT", "[FORCE-UPDATE]", printForceUpdate(Node, VID)) await Driver.controller.nodes.get(Node).pollValue(VID) } @@ -1078,17 +1082,12 @@ module.exports = function (RED) { // Duration Fix function ProcessDurationClass(Class, Operation, Params) { - if (Params.length > 0) { - for (let i = 0; i < Params.length; i++) { - if (typeof Params[i] === "object") { - let Keys = Object.keys(Params[i]); - if (Keys.length === 1) { - if (Keys[0] === "Duration") { - let D = new Duration(Params[i].Duration.value, Params[i].Duration.unit) - Params[i] = D; - - } - } + if (Params.length > 1) { + if (typeof Params[1] === "object") { + let Keys = Object.keys(Params[1]); + if (Keys.length === 1 && Keys[0] === "Duration") { + let D = new Duration(Params[1].Duration.value, Params[1].Duration.unit) + Params[1] = D; } } }