For me to finish the exercise from today (I know already there is a specific counter node) I made the function to get externally defined from topic the max and min limit and the offset (between steeps) considering it will not return any value unless it change in reference to the previous one and latest upper or lower value will be the limits (even if is not matching with the steeps defined)
[{"id":"9606d127.d944f","type":"debug","z":"3a79879.af7b678","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":590,"y":220,"wires":[]},{"id":"1227b68f.ead989","type":"function","z":"3a79879.af7b678","name":"counter","func":"// Get the current value of the 'count' context property - default to 0\nvar count = flow.get(\"count\")||0;\nvar offset = flow.get(\"offset\")||1;\nvar upperlimit = flow.get(\"upperlimit\")||10;\nvar lowerlimit = flow.get(\"lowerlimit\")||0;\nvar previous_count = flow.get(\"previous_count\")||0;\n\nif (msg.topic === \"upperlimit\") {\n // set its value locally\n upperlimit = msg.payload;\n}\n flow.set('upperlimit',upperlimit);\n\n\n\n if (msg.topic === \"lowerlimit\") {\n // set its value locally\n upperlimit = msg.payload;}\n flow.set('lowerlimit',lowerlimit);\n\n\n\nif (msg.topic === \"offset\") {\n // set its value locally\n offset = msg.payload;}\n flow.set('offset',offset);\n\n\n\nif (msg.topic === \"init\") {\n // set its value locally\n count = msg.payload;\n \n \n} else if ((msg.topic === \"increment\") && (count< upperlimit)) {\n count =(count + offset);\n} else if ((msg.topic === \"decrement\") && (count > lowerlimit)) {\n count = (count - offset);\n}\n\nif (count > upperlimit) { count = upperlimit; }\nif (count < lowerlimit) { count = lowerlimit; }\n// Save the new value back to context so it will be available next time\nflow.set('count',count);\n\n// Update the message payload and return - no need to create a new msg\nif ((count <= upperlimit) && (count >= lowerlimit) && (count != previous_count) ) {\n msg.payload = count;\n flow.set('previous_count',count);\nreturn msg;\n}\n\nelse { flow.set('previous_count',count);}\nreturn null\n","outputs":1,"noerr":0,"x":420,"y":220,"wires":[["9606d127.d944f"]]},{"id":"749c878c.234b48","type":"inject","z":"3a79879.af7b678","name":"","topic":"init","payload":"7","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":20,"wires":[["1227b68f.ead989"]]},{"id":"5905f8b1.98de18","type":"inject","z":"3a79879.af7b678","name":"","topic":"increment","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":60,"wires":[["1227b68f.ead989"]]},{"id":"41054bc1.6ff844","type":"inject","z":"3a79879.af7b678","name":"","topic":"decrement","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":100,"wires":[["1227b68f.ead989"]]},{"id":"c2c5272f.aa9128","type":"inject","z":"3a79879.af7b678","name":"","topic":"offset","payload":"5","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":200,"wires":[["1227b68f.ead989"]]},{"id":"20b0d88b.6e82b8","type":"inject","z":"3a79879.af7b678","name":"","topic":"offset","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":160,"wires":[["1227b68f.ead989"]]},{"id":"a1d4d485.501828","type":"inject","z":"3a79879.af7b678","name":"","topic":"offset","payload":"7","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":240,"wires":[["1227b68f.ead989"]]},{"id":"85740ede.cc574","type":"inject","z":"3a79879.af7b678","name":"","topic":"upperlimit","payload":"20","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":400,"wires":[["1227b68f.ead989"]]},{"id":"219dbf9f.aa5b4","type":"inject","z":"3a79879.af7b678","name":"","topic":"upperlimit","payload":"30","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":440,"wires":[["1227b68f.ead989"]]},{"id":"a7373bd3.2d5fd8","type":"inject","z":"3a79879.af7b678","name":"","topic":"upperlimit","payload":"10","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":360,"wires":[["1227b68f.ead989"]]},{"id":"ae72aa3.9ab8158","type":"inject","z":"3a79879.af7b678","name":"","topic":"lowerlimit","payload":"10","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":320,"wires":[["1227b68f.ead989"]]},{"id":"9672da7b.56de58","type":"inject","z":"3a79879.af7b678","name":"","topic":"lowerlimit","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":280,"wires":[["1227b68f.ead989"]]}]
Function re-addressed with some comments to help if someone else is interested
[{"id":"1227b68f.ead989","type":"function","z":"3a79879.af7b678","name":"counter","func":"// Get the current values based on context property - set defaults is not existing\nvar count = flow.get(\"count\")||0;\nvar offset = flow.get(\"offset\")||1;\nvar upperlimit = flow.get(\"upperlimit\")||10;\nvar lowerlimit = flow.get(\"lowerlimit\")||0;\nvar previous_count = flow.get(\"previous_count\")||0;\n\n//set upper limit as per msg.topic received\n\nif (msg.topic === \"upperlimit\") {\n // set its value locally\n upperlimit = msg.payload;\n}\n\nflow.set('upperlimit',upperlimit);\n\n//set lower limit as per msg.topic received\n\n if (msg.topic === \"lowerlimit\") {\n // set its value locally\n upperlimit = msg.payload;\n \n }\n\nflow.set('lowerlimit',lowerlimit);\n\n //set offset between steps as per msg.topic received\n \nif (msg.topic === \"offset\") {\n // set its value locally\n offset = msg.payload;\n}\n \nflow.set('offset',offset);\n\n//set fixed actual count if received as per msg.topic \nif (msg.topic === \"init\") {\n // set its value locally\n count = msg.payload;\n} \n\n// increment or decrement count as per msg.topic if between limits\n \n else if ((msg.topic === \"increment\") && (count< upperlimit)) {\n count =(count + offset);\n} else if ((msg.topic === \"decrement\") && (count > lowerlimit)) {\n count = (count - offset);\n}\n// Set count to upper or lower limit if overshoot\n\nif (count > upperlimit) { count = upperlimit; }\nif (count < lowerlimit) { count = lowerlimit; }\n\n// Save the new value back to context so it will be available next time\nflow.set('count',count);\n\n// Update the message payload and return - no need to create a new msg\nif ((count <= upperlimit) && (count >= lowerlimit) && (count != previous_count) ) {\n msg.payload = count;\n// set previous_count to compare with operation in progress\n\nflow.set('previous_count',count);\nreturn msg;\n}\n\n//Return nothing if not required\nelse { flow.set('previous_count',count);}\nreturn null\n","outputs":1,"noerr":0,"x":420,"y":220,"wires":[["9606d127.d944f"]]}]