OH3 Caddx Binding Widget

Alarm Control Binding based on the CADDX Binding

Caddx Widget-small

Makes use of:
UI Widget: Keypad by Yannick Schaus. Used for the Keypad functionality and was the starting point for the entire project
[OH3 Harmony Widget] () by Craig B. Used for the GUI basis. Used to get the basics of the graphical front end.

Tried to keep the garpics of the widget as similar as I am capable of to the look of the NX-148e keypad. Though had to make some exceptions for functionaility.

Received extensive help on the forum with ides, syntax etc.

The Widget is made up of the Main Graphical Front End (layed out to fit an Android Phone in Portrait Mode), with two additonal Widgets to format the Bypass Zones and Faulted Zones display popups. The widget also relies on an underlying set of rules to send actions to the binding etc. The rules in my setup are TEXT based, however these could be recreated into the UI if required I beleive (easier to share this way too).

The two display widgets could be replaced with a “actionGroupPopupItem” action. However I did not like the display and there do not seem to be any options for formatting the display at all.

The Widget Offers the following settings via the Widget Props:

Partiton Selection Proxy Item - this is a proxy STRING item used to process the Partiton Selection to allow the switching between Partitons within the Widget.
Alarm Feedback Item - used to provide feedback from rules etc in the widget. This item should have the Expire Metadata set to a suitable time with the “Update State” to set state to “-”.
Show Tooltips in Widget - enable or disable Tootips when the widget is running. Nice to have when starting and an easy place to give details, but not required for daily operation.
Mask Character - as per the original Keypad, just a character to mask the CHaracters being entered.

In order to make use of the PROPS, there is a requirement for a standard name convention. I used PartitonX_. There are groups that must comply to this as well. Difficult to list all of them, however a staring point would be:

	<PartitionX>	_Doors			Door Contacts	/ MAG
			        _MotionSensors	Motions Sensors / PIR
			        _Zones			All Zones in a partition
			        _Bypass_Group	Group of all Zone Bypass channel links on each Zone Thing. (Switch, All OFF then OFF, else ON)

	<PartitionX>	_Pin_Number		     Used to carry/activate the disarm function which requires PIN
			        _Armed			     Switch Item linked in Binding
			        _ReadyToArm		     Switch item linked in Binding
			        _ErrorBeepTripleBeep Switch item linked in Binding
			        _EntryGuard		     Switch item linked in Binding
			        _Stay			     Switch to toggle Entry Guard/Stay 
			        _ChimeModeOn         Switch item linked in Binding
			        _Chime			     Switch to toggle Chime 
			        _Exit1			     Switch item linked in Binding
			        _Exit			     Switch to toggle Exit Mode Arming
			        _Pin_Number		     String Item to hold the entered Pin Number

The PartitionX could be changed - would however require editing the Widget Code to replace the Selection actionOptions from Partiton1=1,Partiton2=2,Partiton3=3,Partiton4=4. Additional Partitons could also be added the same way.

As you will notice some of the buttons show a “Not yet Active” tooltips - this is either because I do not have the equipment / configuration or the feature is not yet available in the binding.

I would have liked to play audio on “Triple Beep” error. However Main UI does not at this stage support WebAudio, so had to go with and LED option (ERROR)

I disabled the * and # on keypad. They gave me an error in widget and I don’t think they are required for functionality. Could be removed if required.

The PIN number details need to be filtered from the logs - via the log4j2.xml with REGEX expressions.

To Do list:

  • Combine the two step process to select partition into a single click.
  • Implement Audio Feedback.
  • Make a responsive layout. Found that different devices do not have the same layout. So what looks good on my Android might not look as good on a PC with a Chrome browser.
  • Add missing buttons actions when possible.
  • Integrate the Faulted Zones and Bypass Zones widgets back into main widget.

See errors as follows in the logs. These are intermittent and do not seem to cause issues. Have not been able to determine what the cause is.

2021-04-30 15:10:42.027 [WARN ] [e.internal.SseItemStatesEventBuilder] - Attempting to send a state update of an item which doesn't exist: undefined<Item Suffix>

CaddxFaultedCard.txt (818 Bytes) CaddxBypassCard.txt (899 Bytes)
caddx_graphic_portrait_V1.txt (21.8 KB)
EDIT: Forgot to include .rules file - you will need to replace with your Bridge ID.
Partition1.txt (3.1 KB)

EDIT: Fixed error on ARMED and BYPASS buttons - not using vars for Partiton Selection. Code replaced

EDIT 06/05/2021 Added V2:
caddx_graphic_portrait_V2.txt (26.5 KB)

EDIT 13/07/2021 Added V5:
caddx_graphic_portrait_V5.txt (33.2 KB)

Uses % for layout
Built in Logs, Bypass Zones, Faulted Zones - Toggle with READY, BYPASS and DOWN_ARROW
Only external items is the Feedback item.
EDIT 22/07/2021 Added V6
caddx_graphic_portrait_V6.txt (28.1 KB)
Made some enhancements based on the suggestions by @jossuar . Fully self contained now - no external rules required

Any comments and suggestions welcome.




Well done, looks really great!

1 Like

Hi @Mark_VG,

i did use your widget as an input and simplified it, a bit.
It does not need external rules. It only relies on the items having the default names.
It is responsive and renders correctly also on phones, etc.

It consists of the following two widgets:
caddxKeypad.txt (17.5 KB)
caddxZoneBypass.txt (1.8 KB)

Can you give it a try, to test if it works on a multi partition setup.

Hi Georgios

Gave it a try, but cannot get the alarm to disarm. Looks very good though.

I had updated to more responsive and all into one (excluding rules)

Also using variables instead of items for the pincode

Can you explain:

                                action: command
                                actionItem: CaddxBridge_SendCommand
                                actionCommand: ="partition_secondary_command|4,1"

Also, when selecting the Partition seems to light the incorrect status lights (Armed, Ready, Fire, Power)


EDIT: I have updated my initial post above with my latest version.

EDIT: Managed to get the ARM/DISARM to work. Had to link CaddxBridge_SendCommand Still not sure about the actionCommand though? Also, the Pin does not clear .

EDIT: Looks like Item for PIN is not required in Props? Using variable

Hi @Mark_VG,

i was sure you would figure it out.

The SendCommand channel is nowhere documented. My bad. I have to amend the documentation.
You can send commands to the panel by writing a special formulated string in this channel.
The string consists of two parts separated with a pipe “|”. The first part is the command and the second part is the data of the command. Using this channel you do not need an item for the PIN, you can just send the command directly to the panel.

The most interest is in the following partition commands:

digit1: Pin digit 1
digit2: Pin digit 2
digit3: Pin digit 3
digit4: Pin digit 4
digit5: Pin digit 5 (0 if the system has a 4 digit pin)
digit6: Pin digit 6 (0 if the system has a 4 digit pin)
pfunction: Primary function
   0: Turn off any sounder or alarm
   1: Disarm
   2: Arm in away mode
   3: Arm in stay mode
   4: Cancel
   5: Initiate auto-arm
   6: Start walk-test mode
   7: Stop walk-test mode
partition_mask: Partition mask (number resulting from the addition of the below)
   1: Partition 1
   2: Partition 2
   4: Partition 3
   8: Partition 4
  16: Partition 5
  32: Partition 6
  64: Partition 7
 128: Partition 8

sfunction: Secondary function
   0: Stay (1 button arm / toggle interiors)
   1: Chime (toggle chime mode)
   2: Exit (1 button arm / toggle instant)
   3: Bypass interiors
   4: Fire panic
   5: Medical panic
   6: Police panic
   7: Smoke detector reset
   8: Auto callback download
   9: Manual pickup download
  10: Enable silent exit (for this arm cycle)
  11: Perform test
  12: Group bypass
  13: Auxiliary function 1, 
  14: Auxiliary function 2, 
  15: Start keypad sounder
partition_mask: See above


Instant arm Partition 3: partition_secondary_command|2,4
Fire panic on partition 5: partition_secondary_command|4,16
Disarm all partitions (4 digit PIN 5789): partition_primary_command_with_pin|0x75,0x98,0x00,1,255
Arm partition 3 in stay mode (4 digit PIN 5789): partition_primary_command_with_pin|0x75,0x98,0x00,3,4

With the above info and looking at the widget i posted above, i think you can amend and make your widget more powerful.

Thanks Georgios. Have started to include some of the ideas. Makes sense now.

@jossuar Hi Georgios

Please can you explain this expression to me?

actionCommand: '="partition_secondary_command|1," + (1 << (((vars.selectedPartition === NULL) ? props.selectedPartition : vars.selectedPartition).substr(-1) - 1))'

also need help with the disarm one?

actionCommand: '="partition_primary_command_with_pin|0x" + (vars.pincode).substr(1,1) + (vars.pincode).substr(0,1) + ",0x" + (vars.pincode).substr(3,1) + (vars.pincode).substr(2,1) + ",0x" + (vars.pincode+"00").substr(4,1) + (vars.pincode+"00").substr(4,1) + "," + ((items[((vars.selectedPartition === NULL) ? props.selectedPartition : vars.selectedPartition) + "_Armed"].state === "ON") ? "1" : "2") + "," + (1 << (((vars.selectedPartition === NULL) ? props.selectedPartition : vars.selectedPartition).substr(-1) - 1))'


Hello @Mark_VG,

for the 1st expression:
the property props.selectedPartition has the default selected partition.
the variable vars.selectedPartition holds the actual selected partition by the user.

Both have one of the following values: “Partition1”, “Partition2” … “Partition8”

The following returns the default if no partition is selected by the user.

(vars.selectedPartition === NULL) ? props.selectedPartition : vars.selectedPartition

The following returns one character from the right of selectedPartition var or prop. Its a value from “1” to “8”:


The following returns a number from 0 to 7:

selectedPartition.substr(-1) -1

The (1<<num) is a left shift bit wise operation it shifts the 1 by “num” places to the left.

1<<0 = 1
1<<1 = 2
1<<2 = 4
1<<3 = 8
1<<4 = 16
1<<5 = 32
1<<6 = 64
1<<7 = 128

So the expression is:

'="partition_secondary_command|1," + (1 << (selectedPartition.substr(-1) - 1))'

which in the end will evaluate for Partition1 to the string:


and for Partition3 to the string:


If you look at the previous post for the partition_secondary_command the “1” toggles the chime mode and the 4 is the partition mask.

For more info about the disarm i will get back tomorrow. Its getting late here.

Thank you for the great explanation. Makes it easier to understand. Was a bit confused by the props value as did not seem to be used. Makes sense now though. I have included the Default back into my version as well :slight_smile:

Would appreciate the info about the more complex disarm expression.

Hi @Mark_VG.

A pin code in Caddx can be configured to have a length of 4 or a length of 6 digits.
The command always receives 6 digits. In case of a 4 digit ping digits 5 and 6 are “0”.

Only the substr function is used you can find the definition below:

The string that you can send to the SendCommand channel has the following general format:


The bytes can be written in decimal notation like 17 or in hexadecimal notation like 0x11 (also 17).

A partition primary command has the following format:

Arm/Disarm command analysis
vars.pincode contains the digits entered by the user on the widget.
Say the pincode is “6789” (4 digit pin) then digit1 = “6”, digit2 = “7”, digit3 = “8”, digit4 = “9”
vars.selectedPartition contains “Partition1”, “Partition2”, … “Partition8” according to the selected partition.

"partition_primary_command_with_pin|" +

is the command to be sent followed by the pipe.

"0x" + (vars.pincode).substr(1,1) + (vars.pincode).substr(0,1) + "," +

contains 0x<digit2><digit1>,
The manual states that in the 8 bits of the first byte, we must set the two first digits of the pin.
More specifically the first digit in the lower 4 bits and the second digit in the upper 4 bits.
A byte in hexdeximal notation is written 0xab where “a” are the upper 4 bits and “b” the lower 4 bits.

"0x" + (vars.pincode).substr(3,1) + (vars.pincode).substr(2,1) + "," +

contains 0x<digit4><digit3>,
The same as above for digits 3 and 4.

"0x" + (vars.pincode+"00").substr(5,1) + (vars.pincode+"00").substr(4,1) + "," + 

The same as above for digits 5 and 6.
In case the pincode is only 4 digits long, then the expression (vars.pincode).substr(4,1) would yield an error because substr(4,1) gets the fifth digit. To overcome this condition “00” is added at the end of the pincode, converting it to a 6-digit pin like it is expected by the command.

((items[((vars.selectedPartition === NULL) ? props.selectedPartition : vars.selectedPartition) + "_Armed"].state === "ON") ? "1" : "2") + "," + 

or simpler

((items[vars.selectedPartition + "_Armed"].state === "ON") ? "1" : "2") + "," + 

This calculates the <primary function> to be send to the panel.
If the item “Partition1_Armed” is ON then “1” (Disarm) is sent to the panel.
If the item “Partition1_Armed” is OFF then “2” (Arm in away mode) is sent to the panel.

(1 << (((vars.selectedPartition === NULL) ? props.selectedPartition : vars.selectedPartition).substr(-1) - 1))'

This calculates the partition mask like in the previous post.

Thanks Georgios.

I have uploaded by latest version in the initial post. Thanks for all the support etc.