[SmartThings Edge] Issue with default function to send Z-Wave configuration parameters

Page 177 of the Z-Wave Application Command Class Specification, under section 4.32.1 - Compatability considerations.

2 Likes

Thans for the reply

I understand what you mean, I have to trick the default libraries so that they send the value FFFF (65535), sending the value -1 to the default library function.
I would have to make a code change before sending the value to the defualt function for these specific manufacturers.

I do not want to doubt what you say, since I am not an expert in this and I am sure I am wrong and I do not want you to misunderstand me either, I just want to collaborate

As seen in the link @orangebucket sent, zwave-alliance says that you can use values ​​with signed and unsigned format
There is even an example with size = 2 bytes and the value range from 0 to 65535.

On the other hand, also in the edge libraries it is clear that these formats can be used in the configuration, not only the signed one.

--- @class st.zwave.CommandClass.Configuration.format
--- @alias format st.zwave.CommandClass.Configuration.format
--- @field public SIGNED_INTEGER number 0x00
--- @field public UNSIGNED_INTEGER number 0x01
--- @field public ENUMERATED number 0x02
--- @field public BIT_FIELD number 0x03
local format = {
  SIGNED_INTEGER = 0x00,
  UNSIGNED_INTEGER = 0x01,
  ENUMERATED = 0x02,
  BIT_FIELD = 0x03
}
Configuration.format = format
Configuration._reflect_format = zw._reflection_builder(Configuration.format)

Also If this is going to stay like this, you will have to correct the code to send the AEON_NANO_SHUTTER configuration parameter 35, “openCloseTiming”, profile “stateless-curtain-power-button” to be able to send the values 128 to 255, with size = 1 Byte. with default libraries.
It will give oveflow integer error.

Apart from this, the profile needs in the preference the - name: "openCloseTiming" before the title field to make it work.

name: stateless-curtain-power-button
components:
- id: main
  capabilities:
  - id: statelessCurtainPowerButton
    version: 1
  - id: refresh
    version: 1
  categories:
  - name: Blind
preference:
  - preferenceId: reverse
    explicit: true
  - title: "Open close timing"
    description: "Set the motor's open/close time"
    required: false
    preferenceType: interger
    definition:
      minimum: 5
      maximum: 255
      default: 10
  AEON_NANO_SHUTTER = {
    MATCHING_MATRIX = {
      mfrs = {0x0086, 0x0371},
      product_types = {0x0003, 0x0103},
      product_ids = 0x008D
    },
    PARAMETERS = {
      openCloseTiming = {parameter_number = 35, size = 1}
    }
  }

Thanks agains

1 Like

Actually I may be causing the confusion because I missed this in the spec relating to Configuration V3 and V4:

A device supporting the Configuration Command Class v3 MUST respond to a Configuration Properties Get command. If a Configuration Properties Report command is not returned in response to a Configuration Properties Get command, a controlling device MUST treat the parameter value as a signed integer.

This indicates to me that v3 and v4 do support other types besides signed integers. However, it does appear that we are always serializing a signed value for the configuration parameters regardless of the format (the Configuration format in the ST Lua libs is only used in the Configuration Properties commands)

The workaround provided seems necessary for these situations for the time being, but I will work internally to get the configuration format to be respected when we are sending v3 and v4 Configuration Set commands.

2 Likes

Thanks for bringing this to our attention.

1 Like

@nayelyz, @carter.swedal

Enlarging the size of the parameter value prevents the sending from generating an overflow error in the driver, but it does not work well since the value is interpreted in the device in an erroneous way.

Sending the value with 2’s complement and the correct size does work well to send the value and to configure the device correctly.

For now I will leave it like this in my driver for specific fibaro devices subdrivers.

--- Handle preference changes
---
--- @param driver st.zwave.Driver
--- @param device st.zwave.Device
--- @param event table
--- @param args
local function info_changed(driver, device, event, args)
  local preferences = preferencesMap.get_device_parameters(device)
  for id, value in pairs(device.preferences) do
    if args.old_st_store.preferences[id] ~= value and preferences and preferences[id] then
      local new_parameter_value = preferencesMap.to_numeric_value(device.preferences[id])
      --2's complement value if needed
      if preferences[id].size == 2 and new_parameter_value > 32767 then
        new_parameter_value = new_parameter_value - 65536
      elseif preferences[id].size == 1 and new_parameter_value > 127 then
        new_parameter_value = new_parameter_value - 256
      end
      device:send(Configuration:Set({parameter_number = preferences[id].parameter_number, size = preferences[id].size, configuration_value = new_parameter_value}))
    end
  end
end

Maybe if it is implemented in the main init.lua (info_changed function), sending the value with complement 2 for all values that exceed the corresponding positive range of size 1, 2, 4 would be valid for all cases

Thanks

2 Likes

Hi @carter.swedal

Doing the driver of the Z-Wave parameter configurator I have seen that smartthings default libraries to allow the sending of negative values.
This means that if the parameter is:

  • 1 Byte (0xFF): positive from 0 to 127 and negative from -1 to 128
  • 2 Byte (0xFFFF): positive from 0 to 32767 and negative from -1 to 32768

So far everything perfect, but still disallow sending unsigned values

Some devices like old fibaro, fibaro relay, I do not know if there will be more cases in more manufacturers or models, need send these values:

  • Parameter: 4
  • value : 0 to 65535
  • Size: 2 Bytes

Others like Aeotec Nano Shuter in their driver zwave-window-treatment:

  • parameter: 35
  • value : 5 to 255
  • Size: 1 Byte

As I mentioned in above post, I solved it in my modified drivers by sending the complement to 2 for values ​​> 127 (with 1 Byte) 0 > 32767 (with 2 Byte)
The fibaro devices continues to work fine althoughthe value shown in the CLI when reading is -32768 instead of 65535, because it sends the value in hexadecimal and the device interprets it well, but the CLI and libraries default does not decode fine these values to shown It when received with configuration parameter Get function. Always interprets it as signed values.

In the drivers that do not have this modification like some yours stock, when they send values ​​> 127 (1Byte) or > 32767 (2 Byte) it will give this fatal error and the device will not be configured:

2022-08-13T09:41:26.362964862+00:00 ERROR Z-Wave Device Config Mc Fibaro Single Relay thread encountered error: [string "st/dispatcher.lua"]:233: Error encountered while processing event for <ZwaveDevice: e062ff99 -4cfc-47c2-be7f-91881fdc3a8c [1F] (Fibaro Single Relay)>:
    arg1: table: 0xa56778
[string "st/utils.lua"]:188: bad argument #2 to 'pack' (integer overflow)

The most modern devices I have seen that for values ​​0 to 255, they have a size of 2 bytes and for values ​​0 to 65535 they have a size of 4 bytes

2 Likes

@Mariano_Colmenarejo, thank you for your persistence. I appreciate you helping identify issues with the stock drivers. This is still on my radar, but due to some bandwidth issues it has yet to be fixed.

2 Likes

Thanks for your response.
If the final solution is to change something in the default libraries instead of in the affected drivers, please, if you remember, let us know in case the custom drivers are affected with the solution.

1 Like

Hi @carter.swedal

Hello

I didn’t want to go back on the subject, but I found another error that I don’t know if it’s my mistake or it’s from the default libraries.

When trying to obtain the value of a configuration parameter with the default function:

device:send(Configuration:Get({ parameter_number = parameter_number }))

and I introduce a parameter number greater than 255, I get an error: bad argument #2 to 'pack ’ (unsigned overflow)

2022-08-17T15:11:42.036826361+00:00 INFO Z-Wave Device Config Multi  <ZwaveDevice: e062ff99-4cfc-47c2-be7f-91881fdc3a8c [1F] (Fibaro Single Relay)> emitting event: {"attribute_id":"deviceParameter","capability_id":"legendabsolute60149.deviceParameter","component_id":"main","state":{"value":256}}
2022-08-17T15:11:42.063903027+00:00 DEBUG Z-Wave Device Config Multi  Fibaro Single Relay device thread event handled
2022-08-17T15:11:43.050611028+00:00 TRACE Z-Wave Device Config Multi  Received event with handler capability
2022-08-17T15:11:43.068225361+00:00 INFO Z-Wave Device Config Multi  <ZwaveDevice: e062ff99-4cfc-47c2-be7f-91881fdc3a8c [1F] (Fibaro Single Relay)> received command: {"args":{},"capability":"legendabsolute60149.actionbutton2","command":"push","component":"main","positional_args":{}}
2022-08-17T15:11:43.074040028+00:00 TRACE Z-Wave Device Config Multi  Found CapabilityCommandDispatcher handler in zwave_thing
2022-08-17T15:11:43.079101361+00:00 PRINT Z-Wave Device Config Multi  <<< Action_button:
2022-08-17T15:11:43.084908028+00:00 ERROR Z-Wave Device Config Multi  Fibaro Single Relay thread encountered error: [string "st/dispatcher.lua"]:233: Error encountered while processing event for <ZwaveDevice: e062ff99-4cfc-47c2-be7f-91881fdc3a8c [1F] (Fibaro Single Relay)>:
    arg1: table: 0xc962c8
[string "st/utils.lua"]:188: bad argument #2 to 'pack' (unsigned overflow)

The Configuration statement in the driver is v4

local Configuration = (requires "st.zwave.CommandClass.Configuration")({ version=4 })

I think the range of the parameter values for v4 is from 0 to 65535

For v1 if it is from 0 to 255 or does it apply to all versions?

Thanks

The z-wave spec continues to restrict the range for Configuration:Get and Configuration:Set to 1 to 255. You’ll need to use Configuration:BulkGet and Configuration:BulkSet to access the full range of 1 to 65535.

4 Likes

I hit the unsigned-with-Configuration:Set issue today. Its easy to trigger.

  1. Try and send parameter to device with device:send(Configuration:Set({parameter_number = 10, size = 1, configuration_value = 255}))
  2. [string "st/utils.lua"]:188: bad argument #2 to 'pack' (integer overflow) is logged.

I added the workaround for converting to signed but hoping the correct conversion is added soon.

1 Like

I am seeing this as well while we are developing a new 800 series switch. We are using configuration cc v4 with unsinged integers, but ST is throwing an error when the value is in the higher range (as mentioned multiple times above). I guess I will be converting my values in the time being as a workaround.

Hi @erocm1231

If you are starting device development, one solution is to double the size in bytes of the parameter in the firmware, for example:

If you want to cover a value with a range from 1 to 255, which could be done with 1 Byte unsigned, you assign 2 Bytes to it, so the value 255 is into the first byte of the positive sign.
This is what I have seen that other manufacturers like fibaro are doing in their new devices.

in fibaro dimmer2:
parameter 50, range 0 to 32767 and parameter size=2 ( 2 byte range = 0 to 65535)
parameter 52, range 0 to 32767 and parameter size=2 ( 2 byte range = 0 to 65535)
parameter 53, range 0 to 255 and parameter size=2 ( 2 byte range = 0 to 65535)

- name: "periodicPowerReports"
    title: "periodic power reports - 52"
    description: "This parameter 52 defines in what time interval in sec the periodic power and energy reports are sent. 0 periodic reports disabled"
    required: false
    preferenceType: number
    definition:
      minimum: 0
      maximum: 32767
      default: 3600
- name: "energyReports"
    title: "energy reports - 53"
    description: "This parameter 53 Energy level change which will result in sending a new energy report. 0-energy reports disabled. 1-255 (0.01-2.55 kWh)-report triggering threshold"
    required: false
    preferenceType: number
    definition:
      minimum: 0
      maximum: 255
      default: 10

only use size = 1 when range is max 127

- name: "maximumLevel"
    title: "Maximum brightness level - 2"
    description: "This parameter 2 allows set Maximum brightness level % (2 to 99)"
    required: false
    preferenceType: number
    definition:
      minimum: 2
      maximum: 99
      default: 99
 PARAMETERS = {
      minimumLevel = {parameter_number = 1, size = 1},
      maximumLevel = {parameter_number = 2, size = 1},
      restoreState = {parameter_number = 9, size = 1},
      autoOffTimer = {parameter_number = 10, size = 2},
      autoCalibration = {parameter_number = 13, size = 1},
      forcedOnLevel = {parameter_number = 19, size = 1},
      switchType = {parameter_number = 20, size = 1},
      toggleSwitchStatus = {parameter_number = 22, size = 1},
      doubleClickOption = {parameter_number = 23, size = 1},
      threeWaySwitch = {parameter_number = 26, size = 1},
      sceneActivation = {parameter_number = 28, size = 1},
      onOffMode = {parameter_number = 32, size = 1},
      activePowerReports = {parameter_number = 50, size = 2},
      periodicPowerReports = {parameter_number = 52, size = 2},
      energyReports = {parameter_number = 53, size = 2}
    }

The size has to be defined like this in the firmware of the device for it to work well

If you send the double size as it is now, the error does not appear in the log, but the device does not accept it

1 Like

It’s marked as fixed in beta firmware, not yet in production:

  • Fixed two Z-Wave Configuration Command Class bugs to allow for unsigned, bit mask, and enum parameter type serialization, and 0-sized parameter deserialization in the PropertiesReport Command

So i would guess its coming soon!

1 Like

Only on hubs that will get the 46.x firmware though. Not going to help the ‘wifi’ hubs which lag behind, and what do the other hubs run?

1 Like

I have the latest version of the beta 46.07 firmware and I have tried to send the unsigned parameters and it keeps giving the same error.

[string "st/utils.lua"]:188: bad argument #2 to 'pack' (integer overflow).

Possibly I am doing something wrong, it could be.

Using the command
device:send(Configuration:Set({parameter_number = parameter_number, size = parameter_size_set, configuration_value = parameter_value_send}))

The 2’s complement of the value that exceeds the positive range of the parameter size must continue to be needed to not error and can write the parameter value.

In fact, the stock drivers continue to use this command to send the parameters and always execute it as a signed integer.

I don’t know how to pass arguments to firmware libraries when I want to send an unsigned integer parameter.

The stock Aeotec Nano Shuter driver in their driver zwave-window-treatment:
Preferences:

  • parameter: 35
  • value : 5 to 255
  • Size: 1 Byte

still sending values greater than 127 with a size of 1 Byte which gives the error:
[string “st/utils.lua”]:188: bad argument #2 to ‘pack’ (integer overflow).

On the other hand, I have read parameter 4 of a fibaro relay that has a value of 65535 with a size of 2 Bytes and what it reads is a value = -1, which is the 2’s complement for that value.

2023-01-17T14:57:11.544249993+00:00 TRACE Z-Wave Device Config Mc Received event with handler unnamed
2023-01-17T14:57:11.545296993+00:00 INFO Z-Wave Device Config Mc <ZwaveDevice: 664da0a9-eecb-4f9b-8062-e73135110abf [26] (Fibaro Single Relay)> received Z-Wave command: {args={configuration_value=-1, parameter_number=4, size=2}, cmd_class=“CONFIGURATION”, cmd_id=“REPORT”, dst_channels={}, encap=“NONE”, payload=“\x04\x02\xFF\xFF”, src_channel=0, version=1}

can see the payload, the value in device is 0xFF & 0xFF = 65535

I don’t know what they fixed but this seems not
As I was commenting all the newer devices from different manufacturers I’ve reviewed that have configuration parameters choose parameter sizes as if they were going to use signed integers values even though they only use positive values without sign

@erocm1231

To avoid possible bugs with older devices, in all my drivers I use this 2’s complement conversion before sending configuration or preference parameters.

 --2's complement value if needed
        local parameter_value_send = parameter_value_set
        if parameter_size_set == 4 and parameter_value_set > 2147483647 then
          parameter_value_send = parameter_value_set - 4294967296
        elseif parameter_size_set == 2 and parameter_value_set > 32767 then
          parameter_value_send = parameter_value_set - 65536
        elseif parameter_size_set == 1 and parameter_value_set > 127 then
          parameter_value_send = parameter_value_set - 256
        end
        print("new_parameter_value Sent >>>>",parameter_value_send)

        -- Sent configuration parameter to device
        device:send(Configuration:Set({parameter_number = parameter_number, size = parameter_size_set, configuration_value = parameter_value_send}))
2 Likes

Thank you. I have done something similar, but was only converting for 1 byte values (since that is the only “problem” parameters that we currently have). I like your version as it covers multiple byte scenarios.

2 Likes

@carter.swedal while I understand that you’re trying to follow the z-wave specs to the letter, it does create a problem while porting DTH’s as well as trying to map manufacturers values. The signed value only represents the interpretation of the values, not how the values are transmitted over z-wave.

For example a value of 255 (size 1 byte) will be transmitted as 11111111 over the air. Now the z-wave libraries may treat this as -128 to 127 and the manufacturer’s z-wave device may process this as 0-255, but the underlying value itself hasn’t changed. Keeping mind that DTH’s and Manufacturers are using 0-255 I would like to request that the API’s be extended to allow the driver to send unsigned integers to the command value as ALSO receive unsigned configuration_value back from the received commands so the mapping them to manufacturer specs and porting DTH’s becomes manageable. It seems unreasonable for users to enter a value from -128 to 127 for something like number of seconds where as the manufacturer would be treating them as 0 to 255. Yes it can potentially be handled in the driver by converting them from unsigned to signed and vice versa but it can lead to many mistakes as Mario has pointed out above in the stock drivers as well as overly complicated code which in turn can lead to more errors in production (esp when one driver is supporting 50+ devices with 100+ configuration parameters from different manufacturers all of which seem to be publishing their specs in unsigned numbers). Unsigned numbers worked beautifully with DTH’s and I hope there’s a way to do the same with drivers.

Also, I would request some helper API’s to convert unsigned to signed numbers and vice versa, while we can write it for each driver, it would be very helpful for most devs to use a standard library api for this.

I see your point that despite the spec being clear, manufacturers have done what they want and our need to follow the spec is still causing some pain here.

I would like to request that the API’s be extended to allow the driver to send unsigned integers to the command value

This is possible using ConfigurationSet V3 and V4 commands per the spec, support was added in 0.46.x lua libraries. This is done using format argument.

local Configuration = (require "st.zwave.CommandClass.Configuration")({version=4})
Configuration:Set({
    parameter_number = 13,
    size = 1,
    configuration_value = 255,
    format = Configuration.format.UNSIGNED_INTEGER
})

ALSO receive unsigned configuration_value back from the received commands so the mapping them to manufacturer specs and porting DTH’s becomes manageable.

There is nothing in the ConfigurationReport command that indicates the format of the configuration value, so any solution we implement will still require prior knowledge of this format in the driver. I’ll get something on our backlog to add utility functions for doing 2s-complement to unsigned conversions and visa versa for various sized values, as well as integrate those utilities into functions on the configuration values that are returned from ConfigurationReport commands so the driver can easily convert to whatever type they want for any configuration value.

2 Likes