Hi
I have solved a similar problem with 2 nodes - 1 for logic and the other for the UI
To avoid an infinite loop the "replay op message" is un-ticked
[{"id":"7afa4881.6eb3c","type":"ui_tab","z":"fe45a1b3.8db1a","name":"S1","icon":"dashboard","order":"1"},{"id":"81cecd8b.1c7a4","type":"ui_template","z":"fe45a1b3.8db1a","tab":"7afa4881.6eb3c","name":"ASHP Main Mode","group":"ASHP","order":1,"format":"Mode\n<select ng-model=\"tst\" \nng-options=\"o for o in ['Auto', 'On', 'Off']\" \nng-change = \"msg.payload=tst; msg.topic='Mode'; send(msg)\">\n</select>\n Timer \n<button ng-click=\"msg.payload='-10'; msg.topic='Timer'; send(msg)\" ng-style=\"{width: '35px'}\" ><ng-md-icon icon=\"keyboard_arrow_down\" style=\"fill: black\" ></ng-md-icon></button>\n{{msg.payload}}\n<button ng-click=\"msg.payload='10'; msg.topic='Timer'; send(msg)\" ng-style=\"{width: '35px'}\" ><ng-md-icon icon=\"keyboard_arrow_up\" style=\"fill: black\" ></ng-md-icon></button>\n","storeOutMessages":false,"fwdInMessages":false,"x":290,"y":500,"wires":[["72aeb282.ca9fdc"]]},{"id":"72aeb282.ca9fdc","type":"function","z":"fe45a1b3.8db1a","name":"ASHP Controller","func":"var timer = context.get('timer')||0;\nvar MainMode = context.get('MainMode')||\"\";\nvar MainStatus = context.get('MainStatus')||false;\nvar msg1 = null;\nvar msg2 = null;\nif (msg.topic=='Minute'){\n if (timer > 0){\n timer = Math.max(timer - 1, 0);\n context.set('timer',timer);\n msg1 = {};\n msg1.payload = timer;\n }\n}\nif (msg.topic=='Mode'){\n MainMode = msg.payload;\n context.set('MainMode',MainMode);\n msg1 = {};\n msg1.payload = timer;\n}\nif (msg.topic=='Timer'){\n timer = Math.max(timer + parseInt(msg.payload), 0);\n context.set('timer',timer);\n msg1 = {};\n msg1.payload = timer;\n}\n\nvar NewStatus = false;\nif (timer > 0 || MainMode == 'On'){\n NewStatus = true;\n}\n//console.log(NewStatus, MainStatus, timer)\nif (NewStatus != MainStatus){\n MainStatus = NewStatus;\n msg2 = {};\n msg2.payload = MainStatus;\n context.set('MainStatus',MainStatus);\n}\n\nreturn[msg1, msg2];\n","outputs":"2","noerr":0,"x":280,"y":580,"wires":[["81cecd8b.1c7a4"],["eec15721.e2014"]]},{"id":"f7c659ae.0cdc48","type":"inject","z":"fe45a1b3.8db1a","name":"","topic":"Minute","payload":"1","payloadType":"num","repeat":"5","crontab":"","once":false,"x":100,"y":580,"wires":[["72aeb282.ca9fdc"]]},{"id":"eec15721.e2014","type":"ui_template","z":"fe45a1b3.8db1a","tab":"7afa4881.6eb3c","name":"ASHP Main Status","group":"ASHP","order":1,"format":"<div layout=\"row\" layout-align=\"space-between\">\n <p>Main status</p>\n <p ng-style=\"{color: (msg.payload) == true ? 'green' : 'red'}\">\n {{(msg.payload) == true ? 'Running' : 'Stopped'}}\n </p>\n</div>","storeOutMessages":true,"fwdInMessages":true,"x":530,"y":580,"wires":[[]]}]