I am trying to make a basic calculator

For the sake of getting my head around how to use dashboards, buttons etc, I have set myself a take of building a BASIC calculator.

It only does + - * and /

It is just to get a better understanding of things talking to one another.

Basic idea of the main node which is driving me batty:

It looks at the input stream.
(Two streams - of course.)
One is topic set to NUMBER and the other is FUNCTION.
As it gets numbers, it constructs the first number.
Decimal points are there, but I haven’t got to testing it working yet.

As soon as you press a FUNCTION button, it stores the first number, stores the function and wipes the display.
Then you enter the second number.
It is built with the same code as the first number.

When the = button is pressed, it gets the “function” and applies it to the two numbers and displays the result.

So, in the scheme of things these variables are used/made:
x - the actual digit entered.
count - a running value of the number being entered.
dp - used for the decimal point. As said: not tested as yet.
first_number - the complete number entered before a function key is/was pressed.
new_ - a flag to indicate the first time a number is stored.
function_ - the stored value of the function to apply to the two numbers.

It also supports A/C and C.
A/C wipes all stored data while C clears the values being entered now.

For some weird reason (after a lot of messing around) I am seeing new_ is always set to 1.

Though in saying that I shall have to declare that it does now and then work.

But why, I can’t work it out.

This is a bit of a big-ish bit of code, but most of it is “decorative” (buttons etc)

The main part is the function node called CALCULATOR
The calculator node indicates what it is doing.
As you enter digits, they are shown with a green dot.
As you enter a function, it should be shown with a red dot.
BUT!
If it is the first (only?) time you pressed a function button, the dot should be blue.
My testing keeps showing it as red and if I modify the code (line 26 and changing the text from function_ and change it to new_ and it always shows 1) Dunno how/why.

This has been most of today.

Summary:
It doesn’t seem to detect the function buttons being pressed and saving the first number.
This is because the variable “new_” seems to be 1 when it should be 0.

[{"id":"5ba56956.922298","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"8","order":2,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 8})\"> \n    8\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":350,"y":220,"wires":[["cac1a6b1.afd768"]]},{"id":"13fb7ae4.86f27d","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"5","order":5,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 5})\"> \n    5\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":350,"y":260,"wires":[["a4c5d99e.2a8688"]]},{"id":"18a8ab17.e8bcad","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"2","order":8,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 2})\"> \n    2\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":350,"y":300,"wires":[["81cff506.ecbda8"]]},{"id":"b5489555.4d47f","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"0","order":10,"width":"2","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 0})\"> \n    0\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":190,"y":340,"wires":[["dafd5826.f92e18"]]},{"id":"28865032.701b7","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"7","order":1,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 7})\"> \n    7\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":190,"y":220,"wires":[["3294fdc4.bfa922"]]},{"id":"17c97757.ba2101","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"4","order":4,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 4})\"> \n   4\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":190,"y":260,"wires":[["671c3899.f26b88"]]},{"id":"95e5445.94bdcb8","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"9","order":3,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 9})\"> \n   9\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":510,"y":220,"wires":[["c3517af.47d8e08"]]},{"id":"4568e18b.bcdc18","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"6","order":6,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 6})\"> \n    6\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":510,"y":260,"wires":[["e547f40.5ce739"]]},{"id":"92c05a27.9ec7f8","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"1","order":7,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 1})\"> \n   1\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":190,"y":300,"wires":[["8060eeb2.c25a88"]]},{"id":"a8634ebf.becda8","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":"3","order":9,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 3})\"> \n    3\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":510,"y":300,"wires":[["ca310ba4.a9648"]]},{"id":"3294fdc4.bfa922","type":"link out","z":"8cb984f2.fd98e8","name":"7","links":["79a1b55b.27c30c"],"x":275,"y":220,"wires":[]},{"id":"79a1b55b.27c30c","type":"link in","z":"8cb984f2.fd98e8","name":"Digits in","links":["3294fdc4.bfa922","671c3899.f26b88","8060eeb2.c25a88","81cff506.ecbda8","a4c5d99e.2a8688","c3517af.47d8e08","ca310ba4.a9648","cac1a6b1.afd768","dafd5826.f92e18","e547f40.5ce739","a02457c4.5e4878","5dc91315.307f8c"],"x":375,"y":520,"wires":[["65b53fcf.b9c94"]]},{"id":"671c3899.f26b88","type":"link out","z":"8cb984f2.fd98e8","name":"4","links":["79a1b55b.27c30c"],"x":275,"y":260,"wires":[]},{"id":"8060eeb2.c25a88","type":"link out","z":"8cb984f2.fd98e8","name":"1","links":["79a1b55b.27c30c"],"x":275,"y":300,"wires":[]},{"id":"cac1a6b1.afd768","type":"link out","z":"8cb984f2.fd98e8","name":"8","links":["79a1b55b.27c30c"],"x":435,"y":220,"wires":[]},{"id":"a4c5d99e.2a8688","type":"link out","z":"8cb984f2.fd98e8","name":"5","links":["79a1b55b.27c30c"],"x":435,"y":260,"wires":[]},{"id":"81cff506.ecbda8","type":"link out","z":"8cb984f2.fd98e8","name":"2","links":["79a1b55b.27c30c"],"x":435,"y":300,"wires":[]},{"id":"c3517af.47d8e08","type":"link out","z":"8cb984f2.fd98e8","name":"9","links":["79a1b55b.27c30c"],"x":595,"y":220,"wires":[]},{"id":"e547f40.5ce739","type":"link out","z":"8cb984f2.fd98e8","name":"6","links":["79a1b55b.27c30c"],"x":595,"y":260,"wires":[]},{"id":"ca310ba4.a9648","type":"link out","z":"8cb984f2.fd98e8","name":"3","links":["79a1b55b.27c30c"],"x":595,"y":300,"wires":[]},{"id":"dafd5826.f92e18","type":"link out","z":"8cb984f2.fd98e8","name":"0","links":["79a1b55b.27c30c"],"x":275,"y":340,"wires":[]},{"id":"f13578e6.c5a91","type":"ui_text_input","z":"8cb984f2.fd98e8","name":"","label":"","group":"6e32650f.77da74","order":0,"width":0,"height":0,"passthru":true,"mode":"number","delay":300,"topic":"","x":880,"y":500,"wires":[[]]},{"id":"737465c4.da49cc","type":"ui_template","z":"8cb984f2.fd98e8","group":"3b95c955.711c66","name":".","order":10,"width":"1","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: '.'})\"> \n    .\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":510,"y":340,"wires":[["a02457c4.5e4878"]]},{"id":"a02457c4.5e4878","type":"link out","z":"8cb984f2.fd98e8","name":".","links":["79a1b55b.27c30c"],"x":595,"y":340,"wires":[]},{"id":"68f43f82.fa27f8","type":"ui_template","z":"8cb984f2.fd98e8","group":"f060d0ed.8d867","name":"+","order":3,"width":"2","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: '+'})\"> \n   +\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":770,"y":140,"wires":[["70499019.ca153"]]},{"id":"ea42b834.d0102","type":"ui_template","z":"8cb984f2.fd98e8","group":"f060d0ed.8d867","name":"-","order":6,"width":"2","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: '-'})\"> \n    -\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":770,"y":180,"wires":[["7237794a.1f8eb"]]},{"id":"4842d7a8.d2f4c","type":"ui_template","z":"8cb984f2.fd98e8","group":"f060d0ed.8d867","name":"X","order":9,"width":"2","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 'X'})\"> \n    X\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":770,"y":220,"wires":[["11338844.1a18a8"]]},{"id":"70499019.ca153","type":"link out","z":"8cb984f2.fd98e8","name":"+","links":["5e94c58c.b70d5c"],"x":855,"y":140,"wires":[]},{"id":"7237794a.1f8eb","type":"link out","z":"8cb984f2.fd98e8","name":"-","links":["5e94c58c.b70d5c"],"x":855,"y":180,"wires":[]},{"id":"11338844.1a18a8","type":"link out","z":"8cb984f2.fd98e8","name":"*","links":["5e94c58c.b70d5c"],"x":855,"y":220,"wires":[]},{"id":"f86d73b3.0347b","type":"ui_template","z":"8cb984f2.fd98e8","group":"f060d0ed.8d867","name":"/","order":10,"width":"2","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: '/'})\"> \n    /\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":770,"y":260,"wires":[["c6836d27.f69a68"]]},{"id":"c6836d27.f69a68","type":"link out","z":"8cb984f2.fd98e8","name":"/","links":["5e94c58c.b70d5c"],"x":855,"y":260,"wires":[]},{"id":"20ba0d8.2c81d72","type":"ui_template","z":"8cb984f2.fd98e8","group":"f060d0ed.8d867","name":"=","order":10,"width":"2","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: '='})\"> \n    =\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":770,"y":300,"wires":[["8c34feec.663"]]},{"id":"8c34feec.663","type":"link out","z":"8cb984f2.fd98e8","name":"/","links":["5e94c58c.b70d5c"],"x":855,"y":300,"wires":[]},{"id":"65b53fcf.b9c94","type":"function","z":"8cb984f2.fd98e8","name":"Set topic","func":"msg.topic = \"NUMBER\";\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":520,"wires":[["ab716c5.8c82d9","e083f99c.f1833"]]},{"id":"5e94c58c.b70d5c","type":"link in","z":"8cb984f2.fd98e8","name":"Functions in","links":["11338844.1a18a8","70499019.ca153","7237794a.1f8eb","8c34feec.663","c6836d27.f69a68","caa96648.b5b078","a9e91d3f.b1cc38"],"x":375,"y":480,"wires":[["a994ce0b.9bcd6"]]},{"id":"a994ce0b.9bcd6","type":"function","z":"8cb984f2.fd98e8","name":"Set topic","func":"msg.topic = \"FUNCTION\"\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":480,"wires":[["ab716c5.8c82d9","e083f99c.f1833"]]},{"id":"ab716c5.8c82d9","type":"function","z":"8cb984f2.fd98e8","name":"CALCULATOR","func":"var x = msg.payload;\nvar count = context.get('count') || 0;\nvar dp = context.get('dp')||1;\nif (msg.topic == \"NUMBER\")\n{\n    //\n    node.status({fill:\"green\",shape:\"dot\",text:x});\n    if (x == '.')\n    {\n        // divide by 10 - kinda.\n        x = (x/(10^dp));\n        dp = dp +1;\n        count = count + x;\n    }else\n    {\n        count = (count * 10) + x;\n        context.set('count',count);\n    }\n    msg.payload = count;\n}else\nif (msg.topic == \"FUNCTION\")\n{\n    //\n    var new_ = context.get('new')||0;\n    var function_ = msg.payload;\n    node.status({fill:\"red\",shape:\"dot\",text:function_});\n    if (function_ == 'C')\n    {\n        //  Clear input\n        context.set('count',0);\n        count = 0;\n        msg.payload = 0;\n    }\n    if (function_ == 'AC')\n    {\n        //  All Clear\n        context.set('first_number',0);\n        context.set('count',0);\n        context.set('new_',0);\n        msg.payload = 0;\n    }\n    if (new_ === 0)\n    {\n        //  First time?\n        node.status({fill:\"blue\",shape:\"dot\",text:function_});\n        context.set('first_number',count);    //  save the value in first_number.\n        count = 0;\n        context.set('count',count);\n        new_ = new_ + 1;               //  set flag to say number stored.\n        context.set('new', new_);      //  save.\n        context.set('function',msg.payload);  //save function.\n        msg.payload = 0;               //  \"Clear\" the display.\n    }\n    if (function_ == '=')\n    {\n        //  Here we have to act of the function_ and the two numbers.\n        //  count and context.count.\n        var first_number = context.get('first_number');  //  This is the first.\n        var operation = context.get('function');\n        if (operation == '+')\n        {\n            //  Add\n            msg.payload = first_number + count;\n        }\n        if (operation == '-')\n        {\n            //  Subtract\n            msg.payload = first_number - count;\n        }\n        if (operation == 'X')\n        {\n            //  Multiply\n            msg.payload = first_number * count;\n        }\n        if (operation == '/')\n        {\n            //  Divide\n            msg.payload = first_number / count;\n        }\n\n    }\n\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"x":680,"y":500,"wires":[["f13578e6.c5a91"]]},{"id":"e083f99c.f1833","type":"debug","z":"8cb984f2.fd98e8","name":"Number pressed","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":690,"y":610,"wires":[]},{"id":"d67104c7.a41938","type":"ui_template","z":"8cb984f2.fd98e8","group":"f060d0ed.8d867","name":"C","order":10,"width":"2","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 'C'})\"> \n    C\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":770,"y":340,"wires":[["caa96648.b5b078"]]},{"id":"caa96648.b5b078","type":"link out","z":"8cb984f2.fd98e8","name":"/","links":["5e94c58c.b70d5c"],"x":855,"y":340,"wires":[]},{"id":"a5fa6da7.21c3b8","type":"ui_template","z":"8cb984f2.fd98e8","group":"f060d0ed.8d867","name":"A/C","order":10,"width":"2","height":"1","format":"\n<md-button class=\"vibrate filled touched smallfont rounded\" style=\"background-color:#34495e\" ng-click=\"send({payload: 'AC'})\"> \n    AC\n</md-button> \n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":770,"y":380,"wires":[["a9e91d3f.b1cc38"]]},{"id":"a9e91d3f.b1cc38","type":"link out","z":"8cb984f2.fd98e8","name":"/","links":["5e94c58c.b70d5c"],"x":855,"y":380,"wires":[]},{"id":"3b95c955.711c66","type":"ui_group","z":"","name":"Buttons","tab":"646e95d7.ec6af4","order":3,"disp":true,"width":"3","collapse":false},{"id":"6e32650f.77da74","type":"ui_group","z":"","name":"Display","tab":"646e95d7.ec6af4","order":2,"disp":true,"width":"6","collapse":false},{"id":"f060d0ed.8d867","type":"ui_group","z":"","name":"Functions","tab":"646e95d7.ec6af4","order":4,"disp":true,"width":"4","collapse":false},{"id":"646e95d7.ec6af4","type":"ui_tab","z":"","name":"Calculator","icon":"dashboard","order":12}]

A useful technique when trying to debug a function is to use
node.warn()
statements to follow the flow. For example you could put lines like
node.warn("At point A, new_ = " + new_);
That will display that line in the debug window (and in the node red log) so you can follow the flow of logic through and see where it is going wrong. So in this case put warn’s in each time you set and get the variable from the context and I am sure you will soon see what is going on.

1 Like

So here is how I would trouble shoot this.

  1. get rid of all the ui nodes and replace them with inject nodes so the button that injects 1 would be replaced with an inject of the string ‘1’ and the node to display the result will just be a debug node.

Now when you press an inject, you can see the debug results right away in the backend.

  1. If the function has an issue, add sone debug code to the function - for example in the CALCULATOR node you might want to look at the varible ‘count’ after you hav set it at the top. You could add:
    node.warn("count = " + count);
    to get it displayed in the debug tab. This way you can see what is happening at each press of a key.

good luck.

Ohh yeah, watch the edge cases - first time a button is pressed, what happens if you press an operation button twice in a row, divide by zero etc etc

All,

Thanks again for the node.warn( ) command.

I’ve put it in and found a couple of bugs with the names I used.

Granted I should have seen them sooner.

As I don’t always know the reserved words, if I use one and then realise it, I append it with a ‘_’.

But when I mix up the variable names and the context names… well… Anyway.

While on it, have I got the context stuff right now?

I was told I was using deprecated syntax on a few posts.

Thanks.

Just in conclusion:

With the edits of the variable names and a bit of debugging, it now works.

In answer to the question about pressing two function buttons and what happens:
It remembers and applies the first one.

This whole thing was more a test of buttons, GUI, and a bit more on parsing messages.

I did learn things.

As long as you are using context.set() and context.get() that is ok.

Colin