Capability with Relative Controls?

I am working on a driver for a remote device that has a spinning dial on it. The dial just keep spinning and doesn’t have any stops on it. It only reports direction and speed of the turning which is commonly used for dimming control. I am looking for a presentation in ST that maps well to this. I didn’t want to use a dimmer since I don’t know the actual dim level, only the relative change. Any suggestions?

in the cube I use two capabilities

default dimming level that worked with Smart lights. And I still hope ST will implement state Mirroring

and a custom capability - rotation angle [-270,+270] that resets to zero on timer

this is the best I could squeeze out of the current capability and routine engine.

This makes sense. I figured it would be a custom capability. The second challenge is finding a device that will accept incremental events for the Then portion of the automation. Most lights want an explicit dim level.

@Mariano_Colmenarejo has created special capabilities for that. His driver works with most of the Zigbee lights

I have Smart Knob that that @erickv cretaed driver for, which works like this. If I turn counter clockwise it dicreases the level in increments specified in settings (for eaxmple 10%) or if I turn it clockwice it increses the level.

1 Like

Hi @blueyetisoftware

In the command handler of the custom capability to send the increment +/- level you add the level incremet commanded to the last level status stored

local level = command.args.value
  device:emit_event(level_Steps.levelSteps(level))
  level = level + device:get_latest_state("main", capabilities.switchLevel.ID, capabilities.switchLevel.level.NAME)
  if level > 100 then 
    level = 100
  elseif level < 0 then
    level =0
  end

device:send(zcl_clusters.Level.commands.MoveToLevelWithOnOff(device, math.floor((level)/100.0 * 254), 0xFFFF))
1 Like

That is still using the switchLevel capability though. When I get the info from the device it doesn’t provide a level. Seems like similar devices are just mapping this relative control to an absolute dim level.

I don’t know if I understand you correctly.

Normally, the remote control generates a command with a value.
That value that is sent is used to trigger a routine, which sends a +/- level increase command to a custom capability of the device: legendabsolute60149.levelSteps
The custom capability handler increments or decrements the current level device with the value received from the remote via routine.

I understand now. Your code was from the receiving device, not the device generating the increment/decrement events. I can create the dial with a custom capability, but I just don’t think many devices implement increment/decrement actions like your custom capability does.

Yes, this is the problem.
In the cluster level libraries there is a command that can send steps, I don’t know if all devices support this command

--- @param command_id number
function Level:get_server_command_by_id(command_id)
  local server_id_map = {
    [0x00] = "MoveToLevel",
    [0x01] = "Move",
    [0x02] = "Step",
    [0x03] = "Stop",
    [0x04] = "MoveToLevelWithOnOff",
    [0x05] = "MoveWithOnOff",
    [0x06] = "StepWithOnOff",
    [0x07] = "StopWithOnOff",
    [0x08] = "MoveToClosestFrequency",
  }

Perhaps it would not be necessary to create a custom capability for the bulbs devices.
You could create a handler in the bulb drivers for the command [0x06] = "StepWithOnOff" or [0x02] = “Step”, and create a vid to make it visible in action automations and send the value of the step to that command

If this command were included in the switch level defaults and switchLevel capability it would be wonderful and very easy to use, as is the reset energy command in energy defaults @nayelyz

This is the specification zigbee3.0

16.8.3.3 Step Command Payload
typedef struct
{
uint8 u8StepMode;
uint8 u8StepSize;
uint16 u16TransitionTime;
zbmap8 u8OptionsMask;
zbmap8 u8OptionsOverride;
} tsCLD_LevelControl_StepCommandPayload;
where:
 u8StepMode indicates the direction of the required level change, up (0x00) or
down (0x01)
 u8StepSize is the size for the required level change
 u16TransitionTime is the time taken, in units of tenths of a second, to reach
the target level (0xFFFF means move to the level as fast as possible)
 OptionsMask and OptionsOverride must be either both present or both not
present. These fields are used in creating a temporary Options bitmap from the
u8Options attribute. Each bit of the u8Options attribute is carried across to the
temporary Options bitmap unless the corresponding bit of OptionsMask is set

The resetEnergyMeter command is included in the energyMeter capability definition, that’s why it is in the default handler.
So, if I understand correctly, @blueyetisoftware, for this device, you don’t get a single value (level) and instead, you get two (direction and speed). Then, you need to send them back to the device to change the dimmer value, right?
According to the Zigbee specification, to which cluster do “direction” and “speed” belong and which is their attribute ID? This is to have a better reference

1 Like

It isn’t a zigbee device. It is a LAN remote that emits speed/steps/direction values. I am just trying to figure out how best to expose those to automations so that it is useful. The idea is that someone would want to trigger changes to their volume, dimmer, etc. The issue is that none of those other devices can make use of the speed/steps/direction. Most devices want an explicit value rather than these relative values.

If the audioVolume or switchLevel capabilities had increment/decrement actions, it would be a natural fit. In @Mariano_Colmenarejo’s example above, he made a custom capability to accept these incremental changes, but that only works if I control the target device (speaker, light, etc)

1 Like

Hi @nayelyz
That’s why I used it as an example.

If the “Step” or “StepWithOnOff” command could be added in the switchLevel capability and included in the switchLevel defaults, it would be easy to step level from a routine on any device.

2 Likes

@nayelyz @blueyetisoftware @veonua

The command [0x06] = “StepWithOnOff” works perfectly with the default libraries generated code.
This is the build of the command that matches the zigbee 3.0 specification

--------- level_Steps_handler -----------------

function driver_handler.level_Steps_handler(_, device, command)
local level = command.args.value
  device:emit_event(level_Steps.levelSteps(level))
  
  local direction = 0x00
  if level < 0 then direction = 0x01 end

  device:send(zcl_clusters.Level.commands.StepWithOnOff(device, direction, math.floor((math.abs(level)/100.0 * 254)), 0xFFFF))
end

If this command were included in the switchLevel capabilty, level changes could be executed by steps in any zigbee 3.0 bulb or dimmer

And if the code for command [0x06] = “StepWithOnOff” were included in the switchLevel defaults, it would be wonderful.

Zwave has c.c switchMultiLevel with step_size and up_dwon arguments too

I guess this would require a new feature request, right?

Tested with a Osram Classic, RGBW LIDL TS0505A and LIDL TS0502:

Send step level +10 % from a routine:

2022-10-19T17:27:25.708795265+00:00 PRINT Zigbee Light Multifunction test Level Steps Value = 10.0
2022-10-19T17:27:25.715488931+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> emitting event: {“attribute_id”:“levelSteps”,“capability_id”:“legendabsolute60149.levelSteps”,“component_id”:“main”,“state”:{“value”:10.0}}
2022-10-19T17:27:25.770759598+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> sending Zigbee message: < ZigbeeMessageTx || Uint16: 0x0000, < AddressHeader || src_addr: 0x0000, src_endpoint: 0x01, dest_addr: 0x1786, dest_endpoint: 0x03, profile: 0x0104, cluster: Level >, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x01, seqno: 0x00, ZCLCommandId: 0x06 >, < StepWithOnOff || MoveStepMode: UP, step_size: 0x19, transition_time: 0xFFFF, options_mask: 0x00, options_override: 0x00 > > >
2022-10-19T17:27:25.891948265+00:00 TRACE Zigbee Light Multifunction test Received event with handler zigbee
2022-10-19T17:27:25.910564598+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> received Zigbee message: < ZigbeeMessageRx || type: 0x00, < AddressHeader || src_addr: 0x1786, src_endpoint: 0x03, dest_addr: 0x0000, dest_endpoint: 0x01, profile: 0x0104, cluster: Level >, lqi: 0xBC, rssi: -58, body_length: 0x0007, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x18, seqno: 0x2D, ZCLCommandId: 0x0A >, < ReportAttribute || < AttributeRecord || AttributeId: 0x0000, DataType: Uint8, CurrentLevel: 0x98 > > > >
2022-10-19T17:27:25.938034931+00:00 TRACE Zigbee Light Multifunction test Received event with handler zigbee
2022-10-19T17:27:25.947484931+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> received Zigbee message: < ZigbeeMessageRx ||
type: 0x00, < AddressHeader || src_addr: 0x1786, src_endpoint: 0x03, dest_addr: 0x0000, dest_endpoint: 0x01, profile: 0x0104, cluster: Level >, lqi: 0xBC, rssi: -58, body_length: 0x0005, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x18, seqno: 0x51, ZCLCommandId: 0x0B >, < DefaultResponse || cmd: 0x06, ZclStatus: SUCCESS > > >
2022-10-19T17:27:25.976989598+00:00 TRACE Zigbee Light Multifunction test Found ZigbeeMessageDispatcher handler in zigbee_light_multifunctions
2022-10-19T17:27:25.982488931+00:00 INFO Zigbee Light Multifunction test Executing ZclClusterAttributeValueHandler: cluster: Level, attribute: CurrentLevel
2022-10-19T17:27:25.989038265+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> emitting event: {“attribute_id”:“level”,“capability_id”:“switchLevel”,“component_id”:“main”,“state”:{“value”:60}}

Now Send step level -10 % from a routine:

2022-10-19T17:28:51.724123275+00:00 PRINT Zigbee Light Multifunction test Level Steps Value = -10.0
2022-10-19T17:28:51.730554608+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> emitting event: {“attribute_id”:“levelSteps”,“capability_id”:"legendabsolute60149.levelSteps",“component_id”:“main”,“state”:{“value”:-10.0}}
2022-10-19T17:28:51.765760942+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> sending Zigbee message: < ZigbeeMessageTx || Uint16: 0x0000, < AddressHeader || src_addr: 0x0000, src_endpoint: 0x01, dest_addr: 0x1786, dest_endpoint: 0x03, profile: 0x0104, cluster: Level >, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x01, seqno: 0x00, ZCLCommandId: 0x06 >, < StepWithOnOff || MoveStepMode: DOWN, step_size: 0x19, transition_time: 0xFFFF, options_mask: 0x00, options_override: 0x00 > > >
2022-10-19T17:28:51.919730608+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> received Zigbee message: < ZigbeeMessageRx ||
type: 0x00, < AddressHeader || src_addr: 0x1786, src_endpoint: 0x03, dest_addr: 0x0000, dest_endpoint: 0x01, profile: 0x0104, cluster: Level >, lqi: 0xBE, rssi: -59, body_length: 0x0005, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x18, seqno: 0x53, ZCLCommandId: 0x0B >, < DefaultResponse || cmd: 0x06, ZclStatus: SUCCESS > > >
2022-10-19T17:28:51.961293942+00:00 DEBUG Zigbee Light Multifunction test Luz Mesita device thread event handled
2022-10-19T17:28:51.967211942+00:00 TRACE Zigbee Light Multifunction test Received event with handler zigbee
2022-10-19T17:28:51.977722275+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> received Zigbee message: < ZigbeeMessageRx ||
type: 0x00, < AddressHeader || src_addr: 0x1786, src_endpoint: 0x03, dest_addr: 0x0000, dest_endpoint: 0x01, profile: 0x0104, cluster: Level >, lqi: 0xBA, rssi: -60, body_length: 0x0007, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x18, seqno: 0x2E, ZCLCommandId: 0x0A >, < ReportAttribute || < AttributeRecord || AttributeId: 0x0000, DataType: Uint8, CurrentLevel: 0x7F > > > >
2022-10-19T17:28:52.007636275+00:00 TRACE Zigbee Light Multifunction test Found ZigbeeMessageDispatcher handler in zigbee_light_multifunctions
2022-10-19T17:28:52.013446942+00:00 INFO Zigbee Light Multifunction test Executing ZclClusterAttributeValueHandler: cluster: Level, attribute: CurrentLevel
2022-10-19T17:28:52.019958608+00:00 INFO Zigbee Light Multifunction test <ZigbeeDevice: 84944c69-fa8e-417e-bb62-92b7d5087d63 [0x1786] (Luz Mesita)> emitting event: {“attribute_id”:“level”,“capability_id”:“switchLevel”,“component_id”:“main”,“state”:{“value”:50}}

2 Likes

Hi, @blueyetisoftware

The formal request to create a capability that fits your need has been made to the team, but I wouldn’t expect high priority on this since it can easily be bypassed using a switchLevel or even by creating your own custom capability. Also, I think not many devices can use a capability like this.

2 Likes

every Zigbee device can use it. It’s been in the protocol for years. The rotation wheel was a basic design for increasing and decreasing brightness even before my birth.

What is the purpose of the “proposed” field in the capabilities and how do we move from proposed to published?
Is there any procedure we should go to get the capability “official”?

Hi, @veonua & @blueyetisoftware

LIVE capabilities are immutable and supported in all applicable APIs, since they have been fully tested.

But you are talking about a switchLevel with a different shape. This rotation wheel proposed by @blueyetisoftware just reports speed and direction, so you wouldn’t be able to set a brightness value turning that wheel unless you define a mapping table that turns current value + speed + direction into a brightness value, but that would be way more complicated than using the switchLevel. I know that @blueyetisoftware said

but I am not so sure how natural that transition would be. There has to be some logic somewhere that translate all those attributes into a numerical value.

That logic would need to be in the target device itself. If it had an increment command, it would take its current value and add 1, or some other provided value, to its existing value. I would never need to know the current value. It’s a stateless control. This is how Philips Hue designs controls. They are stateless. The smarts are in their hub and lights.