Taking a global source 3 digit number split into individual numbers and send IR commands based upon the individual numbers

What I want to do is take a number entered and pass along this number as IR codes to flash a channel change on a Dish receiver with Global Cache'. My question is how do I take the individual numbers 2, 0, 4 in this example and create maybe an if/then statement(s). So, if the number is 2, then send that IR command, followed by if it is 0, then that IR command and finally if 4, then that IR command? There is a 0-9 keypad - I'm thinking a possibility of just 10 if/then statements. But, I'm very new to Node-Red so maybe there is a better option? I have the individual IR commands for each number, the global cache node-red node, just don't know how to check for a number and send the appropriate command in Node-Red.

I have the following default channel button sets a up to a three digit number and creates a global source called source2, the trigger is set to fire thru the function and the number is split.

// Convert a 3-digit numeral into individual numerals
function convertNumeral(numeral) {
  // Split the numeral into an array of digits
  var digits = numeral.toString().split("");

  // Return the array of digits
  return digits;
}

// Convert the msg.payload to individual numerals
msg.payload = convertNumeral(msg.payload);

// Return the message
return msg;

The code above takes the number and outputs it into individual numbers i.e., 204 is sent as 2, 0, 4

My function node has the following debug:

Feed the function output into Split node and it will convert it into three messages, one with each of the digits in msg.payload.

Colin Thanks!

I split the function node choosing array with fixed length of 1. It did send three separate messages out. How do I then get the system to send IR commands based upon these split numbers? Maybe put the output in a switch node or another function node? I did get ChatGTP to create some code, but I haven't worked through it yet...it is below:

var objects = msg.payload;

objects.forEach(function(obj) {
    var num1 = obj.num1;
    var num2 = obj.num2;
    var num3 = obj.num3;
    // Your logic to generate IR command based on num1, num2, and num3
    // For demonstration, just printing the numbers
    console.log("Num1: ", num1, ", Num2: ", num2, ", Num3: ", num3);
    
var objects = msg.payload;

objects.forEach(function(obj) {
    var num1 = obj.num1;
    var num2 = obj.num2;
    var num3 = obj.num3;
    // Your logic to generate IR command based on num1, num2, and num3
    // For demonstration, just printing the numbers
    console.log("Num1: ", num1, ", Num2: ", num2, ", Num3: ", num3);
    
// Sending an IR command using the globalcache-out node
// Replace "globalcache-out" with the actual ID of your globalcache-out node
// This example sends an IR command based on num1, num2, and num3
// Adjust the payload format as required by the globalcache-out node
node.send({
    topic: "globalcache-out",
    payload: {
        type: "ir",
        data: {
            format: "pronto",
            value: "0000 0073 0000 000E 0080 0040 0010 0010 0010 0040 0010 0010 0010 0040 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0040 0010 0010 0010 0010 0010 0010 0040 0010 0010 0010 0010 0040 0010 0010 0010 0010 0040 0010 0040 0010 0010 0010 0AD7"
        }

With the code you originally had, put a split node after the function node. (As @Colin said)

Then the payloads being sent will be 2 0 and 4.

Then put a delay node and set it to rate limit. And put a 1 second delay.

Then going out of the delay node will be 2 (1 second pause) 0 (1 second pause) and 4.

That would then be sent into your node to send the IR codes.

EDIT

Ok, maybe not quite that simple.

After the delay node put another function node and put this in it.

// Sending an IR command using the globalcache-out node
// Replace "globalcache-out" with the actual ID of your globalcache-out node
// This example sends an IR command based on num1, num2, and num3
// Adjust the payload format as required by the globalcache-out node
node.send({
    topic: "globalcache-out",
    payload: {
        type: "ir",
        data: {
            format: "pronto",
            value: "0000 0073 0000 000E 0080 0040 0010 0010 0010 0040 0010 0010 0010 0040 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0040 0010 0010 0010 0010 0010 0010 0040 0010 0010 0010 0010 0040 0010 0010 0010 0010 0040 0010 0040 0010 0010 0010 0AD7"
        }

As it would seem that bit of the code wants single digits in the payload.
(I think)

As you are new to NR, I would suggest not trying to do everything in one node.
I can lead to confusion at this point.
(Well it did for me)

Good luck.

What hardware are you using to send the IR command?

Colin - I'm using global cache' GC-100-18R. I have two of these with 6 IR ports each (12 total).

Thanks! I'm new to NR. I'll work thru this I also have 12 receivers I need to set the default channels on. So, I figured I would get it working for 1 and then the other 11 would fall into place.

Have you worked out how you are going to communicate with that device from node-red?

I have the following configured so far, thanks to your help! I have a couple questions:

  1. What do you think? Is there a better way?
  2. I'm having trouble with leading zeros typed into the default channel entry. They are cut off, unsure if that matters yet, but might need to have 012 for example and not just send 12...I thought about using the numeric input, but it doesn't allow for the leading 0 either, plus too many up/dn presses to get to the correct number.

My 2nd function node after the split has the following code

// Define IR commands for numbers 0 to 9
var irCommands = [
    "1,58000,1,37,23,351,23,164,23,94,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,94,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",// IR command for the number 0
    "1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",// IR command for the number 1
    "1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",// IR command for the number 2
    "IR Command for 3",
    "IR Command for 4",
    "IR Command for 5",
    "IR Command for 6",
    "IR Command for 7",
    "IR Command for 8",
    "IR Command for 9"
];

// Extracting input numbers from msg.payload
var number0 = msg.payload[0];
var number1 = msg.payload[1];
var number2 = msg.payload[2];

// Constructing the IR commands based on the input numbers
var irCommand0 = irCommands[number0];
var irCommand1 = irCommands[number1];
var irCommand2 = irCommands[number2];

// Sending IR commands through Global Cache
// Assuming you have configured the Global Cache node and set it to send IR commands via msg.ir
msg.ir = [
    { payload: irCommand0 },
    { payload: irCommand1 },
    { payload: irCommand2 }
];

// Send the modified message to the next node
return msg;type or paste code here

This does this in the debug complete message product for the number 144 entered.

5/1/2024, 3:17:00 PMnode: ae4ac7fda09a80a8
Payload : msg : Object
object
info: object
tag: "Scheduler"
topic: "Payload"
payload: "1"
_payload: undefined
parts: object
id: "5d3cb5478c3e5a3b"
type: "array"
count: 3
len: 1
index: 0
_msgid: "034a0118b61c096c"
ir: array[3]
0: object
payload: "1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351"
1: object
payload: undefined
2: object
payload: undefined
5/1/2024, 3:17:01 PMnode: ae4ac7fda09a80a8
Payload : msg : Object
object
info: object
name: "Trigger 5AM"
state: undefined
trigger: object
tag: "Scheduler"
topic: "Payload"
payload: "4"
_payload: undefined
parts: object
id: "5d3cb5478c3e5a3b"
type: "array"
count: 3
len: 1
index: 1
_msgid: "a7263fd21b61caaa"
ir: array[3]
0: object
payload: "IR Command for 4"
1: object
payload: undefined
2: object
payload: undefined
5/1/2024, 3:17:02 PMnode: ae4ac7fda09a80a8
Payload : msg : Object
object
info: object
tag: "Scheduler"
topic: "Payload"
payload: "4"
_payload: undefined
parts: object
id: "5d3cb5478c3e5a3b"
type: "array"
count: 3
len: 1
index: 2
_msgid: "56677b6778458f5b"
ir: array[3]
0: object
payload: "IR Command for 4"
1: object
payload: undefined
2: object
payload: undefined

This is right as I do not have IR commands setup for 4 in the code. I haven't tested if it will send the actual IR commands out (working on that)...

Let's take it one step at a time.

So what you have is now working?

I see a global cache mentioned.

Change it's name to reflect which sensor's data is used in it and edit/change the code for each iteration to read that particular cache's data.

That's one way.
:person_shrugging:

Try searching for
global cache GC-100-18R

I have that it spits out the correct IR code to the debug node. I have the GC node configured correctly and I'm using it else where with success on source 11. I have a remote control setup that is working thru NR.

I know the debug node is hard to read, but above (last message) I have the debug information if that helps? It almost appears that the data housed within the payload is not getting sent out of the function node correctly..? I.e. 1,4,4 is getting sent versus the actual IR codes? Or, maybe it is encapsulated as part of a bigger set of data and GC doesn't know how to get the IR data...?

So, I'm having the user pick a default channel and it is getting saved as a global source2. A trigger node is going to take that info and fire an IR command to a specific receiver to default it's channel back to the chosen channel...

Thanks
Jason

Ok, made some changes - this is what I have now. It is taking the IR commands and correctly putting them in a global context called matchedCommands; however, it is not sending them out through the global cache out node, which is configured like my others that are working...Any advice?

Split(array)

// Check if source2 is a number
if (typeof source2 === 'number') {
    // Convert source2 to a string to check its length
    var source2String = source2.toString();

    // Check if source2String has 1, 2, or 3 digits
    if (source2String.length <= 3) {
        // Proceed with processing
        // Convert source2String to an array of digits
        var numberArray = source2String.split('').map(Number);

        // Validate the number array
        if (Array.isArray(numberArray)) {
            // Initialize an array to store matched IR commands
            var matchedCommands = [];

            // Map each digit to its corresponding IR command
            numberArray.forEach(function(digit) {
                // Ensure the digit is within the range 0-9
                if (digit >= 0 && digit <= 9) {
                    var command = irCommands[digit];
                    // Push the command to the array of matched commands
                    matchedCommands.push(command);
                } else {
                    node.warn("Invalid digit: " + digit);
                }
            });

            // Store the array of matched commands in the global context
            global.set("matchedCommands", matchedCommands);
        } else {
            node.error("Invalid number array: " + numberArray);
        }
    } else {
        // Handle the case when source2 has more than 3 digits
        node.error("default channel should be up to a three-digit number.");
    }
} else {
    // Handle the case when source2 is not a number
    node.error("Default channel must be a 1, 2 or 3 digit number.");
}

Assign IR Cmds

// Retrieve the number array from the message payload
var numberArray = msg.payload;

// Log the received number array to debug
node.warn("Received number array: " + JSON.stringify(numberArray));

// Define IR commands for 0-9
var irCommands = [
    // ir command 0
    "1,58000,1,37,23,351,23,164,23,94,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,94,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    // ir command 1
    "1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    //ir command 2
    "1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    //ir command 3
    "1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    //ir command 4
    "1,58000,1,37,23,351,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    //ir command 5
    "1,58000,1,37,23,351,23,164,23,164,23,94,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    //ir command 6
    "1,58000,1,37,23,351,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    //ir command 7
    "1,58000,1,37,23,351,23,164,23,164,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    //ir command 8
    "1,58000,1,37,23,351,23,164,23,164,23,94,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351",
    //ir command 9-4
    "1,58000,1,37,23,351,23,164,23,164,23,94,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351"
];

// Validate the number array
if (Array.isArray(numberArray)) {
    // Initialize an array to store matched IR commands
    var matchedCommands = [];

    // Map each digit to its corresponding IR command
    numberArray.forEach(function(digit) {
        // Ensure the digit is within the range 0-9
        if (digit >= 0 && digit <= 9) {
            var command = irCommands[digit];
            // Push the command to the array of matched commands
            matchedCommands.push(command);
        } else {
            node.warn("Invalid digit: " + digit);
        }
    });

    // Store the array of matched commands in the global context
    global.set("matchedCommands", matchedCommands);
} else {
    node.error("Invalid number array: " + numberArray);
}

// Return the message
return msg;

Send to GC

// Retrieve matchedCommands array from global context
var matchedCommands = global.get('matchedCommands');

// Check if matchedCommands is defined and is an array
if (Array.isArray(matchedCommands)) {
    // Iterate over each IR command in the matchedCommands array
    matchedCommands.forEach(function(irCommand) {
        // Construct a message object with the IR command as the payload
        var msgToSend = {
            payload: irCommand
        };
        
        // Send the message to the Global Cache - IR Command node
        node.send(msgToSend);
    });
} else {
    // Handle the case when matchedCommands is empty or not an array
    node.error("No matched IR commands found in the global context.");
}

Iterate ea IR Cmd.

// Iterate over each IR command in the matchedCommands array
for (var i = 0; i < matchedCommands.length; i++) {
    // Construct a message object with the IR command as the payload
    var msgToSend = {
        payload: matchedCommands[i]
    };

    // Send the message to the Global Cache - IR Command node
    node.send(msgToSend);
}
// Return the message
return msg;

Here is my Global Context data for the matchedCommands array, which appears to be right...

["1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351","1,58000,1,37,23,351,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351","1,58000,1,37,23,351,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351"]

EDIT:

It is working now. To make it start sending-I didn't need the Iterate over ea IR command function.

One last question...Is there a way to ensure that the default source created is only a 1, 2 or 3 digit number on the web interface?

image

I'm using a text interface mode set to number because there are many channels and I didn't want someone to have to hit the up/dn arrow a bunch of times for input. So, no they simply type in this field. However, you can type more than 3 digits and/or text as well. The code is set to stop any of this from going thru in the Split(array) function; however, the user doesn't see a message...it simply doesn't work. I would like to have a message to the user that it needs to be a 1, 2 or 3 digit number and popup if they do not set the default channel correctly. Is there a way to do this?

Here is what I have for the user form submission now to verify only a 1, 2 or 3 digit number input; however, this code isn't sending anything out to the debug node on a user entering in a correct number and hitting submit. My change node is wired to the template node and the rule is set the Global.source2 to the msg.payload. Any advice, maybe a problem with the browser?

<!-- HTML input field -->
<input type="text" id="userInput" placeholder="Enter a number">
<button onclick="submitInput()">Submit</button>
<p id="errorMessage" style="color: red;"></p>

<script>
// Function to handle form submission
function submitInput() {
    // Get the input value
    var inputValue = document.getElementById("userInput").value;

    // Clear any previous error message
    document.getElementById("errorMessage").innerText = ""; // Clear the error message

    // Check if the input is a valid number
    if (/^\d{1,3}$/.test(inputValue)) {
        // If it's valid, send the input value to the next node
        msg = { payload: inputValue }; // Initialize msg object
        console.log("Input value:", inputValue); // Debugging statement
        node.send(msg); // Send the message to the next node in the flow
    } else {
        // If it's not valid, show an error message
        document.getElementById("errorMessage").innerText = "Please enter a valid 1, 2 or 3 digit number.";
    }
}
</script>

Well, if you want to set a default value to be sent as though you entered the value in the text input node:

Put an inject node before that node with the default value you want AND set the text input node and tick the if message arrives at input, pass it to output.

With me?

As the data the user is entering is a String - then you can use a simple string length function - if the length is < 3 - either error or pad at start with a zero, if it is 3 then pass it on to your function node, or if it is greater than 3 - then throw an error and display a message to the user

Craig

Thanks! Initially my text node would send data into a change node which created a global source. I have an eztimer node which at 5am every morning, right now, will send the global source created through the functions and end up sending IR commands out to the global cache node. This was working fine when it was just the text node and the change node. I wanted to add in functionality to only allow a 1, 2, or 3 digit number and nothing else, which is why I created a template. My problem right now is this template will not send out data to the change node for the global source to be created. There is something in my template coding that won't allow...just cannot figure out what yet?

Craig thanks! My template is working in this regard it is just not sending it out to the change node for the global source to be created. The template looks for only a 1, 2 or 3 digit number, if there is anything else it displays an error.

Sorry what do you mean by my Template ?? It can mean many different things on this forum so need clarity to make sure we are talking about the same thing.

Also need to be careful about confusion you are talking global source, global cache and you have a global device - again these are terms that mean something in NR also

Craig