Examples added

This commit is contained in:
rawee 2023-02-18 18:25:37 +05:30
parent e60da7078a
commit f4884fe55b
9 changed files with 459 additions and 162 deletions

130
README.md
View File

@ -65,6 +65,7 @@ Admin Node generate QR Code just below the node for easy connection with whatsap
3. **Chats / Group Out** : As simple as mention on name, node will send `msg.payload` recived at input to the number mentioned in node.
A reply to All example is avilable in examples to import.
MultiMedia Message: Requirments-
| Input | Description |
@ -86,6 +87,7 @@ Admin Node generate QR Code just below the node for easy connection with whatsap
## Button, List and TemplateButton
Supported in Whatsapp-Lite only, `TODO for Whatsapp-Web`.
A Complete Button-Bot example is avilable in Node examples.
* <b>Simple Button </b>For simple 3 Bottons your `msg.paylod` should be...
@ -140,133 +142,10 @@ msg.payload = {
```
Yes its lot require for buttons, A node will come soon to minimize these effors.
You may direct import these test button with bellow code.
You may direct import these test buttons from the Node Examples.
```json
[
{
"id": "6fe81f4418014185",
"type": "inject",
"z": "a133618d7af8d486",
"name": "Sample button Text",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 130,
"y": 180,
"wires": [
[
"ad52615eb46ed55b"
]
]
},
{
"id": "cf275a62edbc347f",
"type": "inject",
"z": "a133618d7af8d486",
"name": "Smart Button Test",
"props": [
{
"p": "topic",
"v": "",
"vt": "date"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 130,
"y": 140,
"wires": [
[
"f5fbed87687de5b7"
]
]
},
{
"id": "f5fbed87687de5b7",
"type": "function",
"z": "a133618d7af8d486",
"name": "TempButton",
"func": "msg.payload = {\n text: \"Hi it's a template message by Node-RED 👍 to Test\",\n footer: 'Hello I am footer of message.',\n templateButtons: [\n {\n index: 1,\n urlButton: {\n displayText: '⭐ Vist Node-RED',\n url: 'https://nodered.org/'\n }\n },\n {\n index: 2,\n callButton: {\n displayText: 'Call me!',\n phoneNumber: '+1 (234) 5678-901'\n }\n },\n {\n index: 3,\n quickReplyButton: {\n displayText: 'Click me I am Button',\n id: 'id-like-buttons-message'\n }\n },\n {\n index: 4,\n quickReplyButton: {\n displayText: '🖱️ Sample Button',\n id: 'button-id-no-space'\n }\n }] \n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 370,
"y": 140,
"wires": [
[
"9caf4dd912ca82f6"
]
]
},
{
"id": "ad52615eb46ed55b",
"type": "function",
"z": "a133618d7af8d486",
"name": "Button",
"func": "msg.payload = {\n text: \"Hi it's button message\",\n footer: 'Hello World',\n headerType: 1,\n buttons: [\n {buttonId: 'id1', buttonText: {displayText: 'Button 1'}, type: 1},\n {buttonId: 'id2', buttonText: {displayText: 'Button 2'}, type: 1},\n {buttonId: 'id3', buttonText: {displayText: 'Button 3'}, type: 1}\n ]\n }\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 350,
"y": 180,
"wires": [
[
"9caf4dd912ca82f6"
]
]
},
{
"id": "670571eb76e4d237",
"type": "comment",
"z": "a133618d7af8d486",
"name": "Connect them to Chats-Out Node. ",
"info": "Dont foget mobile no.",
"x": 160,
"y": 100,
"wires": []
},
{
"id": "9caf4dd912ca82f6",
"type": "chats-out",
"z": "a133618d7af8d486",
"name": "Chats Out",
"whatsappLink": "whatsapp-web",
"number": "",
"x": 620,
"y": 160,
"wires": []
},
{
"id": "3e0550933ed06e84",
"type": "comment",
"z": "a133618d7af8d486",
"name": "Mention Your Phone No. in node.",
"info": "",
"x": 610,
"y": 120,
"wires": []
}
]
```
5. **Reply Node** : In Beta mode.
5. **Reply Node** : In Beta mode. (Chats-out Node can be used instead of reply node)
Node will reply(the `payload`) on each message starting with string mentioned in instruction coloum or defaults `!red`. Avoid using it please.
@ -282,6 +161,7 @@ Issues and Suggestions are welcome [here.](https://github.com/raweee/node-red-co
* `Ver-0.1.32` : Socket based `Whatsapp Lite` config node added in beta mode. Image message sending support added in chats-out node.
* `Ver-0.1.33` : Button and list support added, Minnor bugs fixed.
* `Ver-0.1.34` : Multiple Events reading options are added in Chats-In Node.
* `Ver-0.1.36` : Check box added to show status as `Online/Offline` in Whatsapp-Link Node, to get push notifications. Ping-Interval added to keep whatsapp alive for long time. Multiple examples added.
## Future Nodes
Currently working on more Whatsapp Node and will be avilable soon -

View File

@ -72,6 +72,9 @@ module.exports = function(RED) {
msg.from = msg.key.participant || msg.key.remoteJid;
msg.from = msg.from.replace(/\D/g, '') || msg.from;
msg.chatID = msg.key.remoteJid.replace(/\D/g, '') || msg.key.remoteJid ;
if(msg.message.extendedTextMessage){
return null
}
node.send(msg)
})
});

View File

@ -28,7 +28,7 @@
</div>
<div class="form-row">
<label for="node-input-number"><i class="fa fa-address-card-o"></i> Number</label>
<input type="text" id="node-input-number" placeholder="Mobile Number..">
<input type="text" id="node-input-number" placeholder="Mobile or Group Number..">
</div>
<div class="form-tips">
<p>Don't forget to mention international dialing code befor your number.

248
examples/Button Bot.json Normal file
View File

@ -0,0 +1,248 @@
[
{
"id": "595bb93a55a7385e",
"type": "tab",
"label": "Whatsapp-Button-Bot",
"disabled": false,
"info": "",
"env": []
},
{
"id": "d078d4c37dcddbfd",
"type": "chats-in",
"z": "595bb93a55a7385e",
"name": "Chats In",
"whatsappLink": "45549bbfeb38499a",
"whatsappLiteevent": "messages.upsert",
"whatsappWebevent": "",
"x": 80,
"y": 180,
"wires": [
[
"b6b28a9e9b416545",
"456aeee272c23848"
]
]
},
{
"id": "b6b28a9e9b416545",
"type": "switch",
"z": "595bb93a55a7385e",
"name": "Get #hi",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "#hi",
"vt": "str"
},
{
"t": "eq",
"v": "#Hi",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 280,
"y": 120,
"wires": [
[
"8eb6e842afc48bf9"
],
[
"8eb6e842afc48bf9"
]
]
},
{
"id": "8eb6e842afc48bf9",
"type": "function",
"z": "595bb93a55a7385e",
"name": "To get the #hi",
"func": "msg.payload = {\n text: \"Hi, This a test message for buttons, try selecting any option below.\", //String\n footer: `I'm just a footer.`, //String\n headerType: 1, //keep it \"1\" only.\n buttons: [ // Array of buttons.\n {buttonId: 'id1-string', buttonText: {displayText: 'Simple Reply'}, type: 1},\n {buttonId: 'id2-tempMessage', buttonText: {displayText: 'Temp. Button'}, type: 1},\n {buttonId: 'listMessage-id3', buttonText: {displayText: 'List Message'}, type: 1}\n ]\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 480,
"y": 120,
"wires": [
[
"b6f984dbcae75a69",
"32b120bcdc2446d0"
]
]
},
{
"id": "b6f984dbcae75a69",
"type": "chats-out",
"z": "595bb93a55a7385e",
"name": "Chats Out",
"whatsappLink": "45549bbfeb38499a",
"number": "",
"x": 700,
"y": 220,
"wires": []
},
{
"id": "456aeee272c23848",
"type": "switch",
"z": "595bb93a55a7385e",
"name": "Get Button Response",
"property": "message.buttonsResponseMessage.selectedButtonId",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "id1-string",
"vt": "str"
},
{
"t": "eq",
"v": "id2-tempMessage",
"vt": "str"
},
{
"t": "eq",
"v": "listMessage-id3",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 260,
"y": 320,
"wires": [
[
"351cb37bbcb7d1dc"
],
[
"c8565e37aefa1654"
],
[
"2d81ceeaf0b1f07a"
]
]
},
{
"id": "32b120bcdc2446d0",
"type": "debug",
"z": "595bb93a55a7385e",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 690,
"y": 400,
"wires": []
},
{
"id": "351cb37bbcb7d1dc",
"type": "function",
"z": "595bb93a55a7385e",
"name": "Mention Reply",
"func": "\nmsg.payload = {\n text: `Hi @${msg.from}, hello from Tomato Bot.`, \n mentions: [`${msg.key.remoteJid}`]\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 480,
"y": 280,
"wires": [
[
"b6f984dbcae75a69",
"32b120bcdc2446d0"
]
]
},
{
"id": "c8565e37aefa1654",
"type": "function",
"z": "595bb93a55a7385e",
"name": "Temp. Button",
"func": "msg.payload = {\n text: \"Hi it's a template message 👍 to Test\",\n footer: 'Hello I am footer of message.',\n templateButtons: [\n {index: 1, urlButton: {displayText: '⭐ Vist Node-RED', url: 'https://nodered.org/'}},\n {index: 2, callButton: {displayText: 'Call me!', phoneNumber: '+1 (234) 5678-901'}},\n {index: 3, quickReplyButton: {displayText: 'Click me I am Button', id: 'I-am-button-id-without-space'}},\n {index: 4, quickReplyButton: {displayText: '🖱️ Sample Button 2', id: 'button-2-was-clicked'}}\n ]\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 470,
"y": 320,
"wires": [
[
"b6f984dbcae75a69",
"32b120bcdc2446d0"
]
]
},
{
"id": "2d81ceeaf0b1f07a",
"type": "function",
"z": "595bb93a55a7385e",
"name": "List Button",
"func": "msg.payload = {\n text: \"This is a list\",\n footer: \"nice footer, link: https://google.com\",\n title: \"Amazing boldfaced list title\",\n buttonText: \"Required, Tap to see List\",\n sections : [{\n title: \"Section 1\",\n rows: [\n {title: \"Option 1\", rowId: \"option1\"},\n {title: \"Option 2\", rowId: \"option2\", description: \"This is a description\"}\n ]},\n {\n title: \"Section 2\",\n rows: [\n {title: \"Option 3\", rowId: \"option3\"},\n {title: \"Option 4\", rowId: \"option4\", description: \"This is a description V2\"}\n ]\n }]\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 470,
"y": 360,
"wires": [
[
"b6f984dbcae75a69",
"32b120bcdc2446d0"
]
]
},
{
"id": "03ed98e4d8a123e1",
"type": "comment",
"z": "595bb93a55a7385e",
"name": "Socket Client Only",
"info": "Connect with whatsapp Lite (socket client) only",
"x": 110,
"y": 140,
"wires": []
},
{
"id": "ef67038c9dbff9d1",
"type": "comment",
"z": "595bb93a55a7385e",
"name": "To get #hi from user and reply a button",
"info": "Connect with whatsapp Lite (socket client) only",
"x": 390,
"y": 80,
"wires": []
},
{
"id": "08eb70757179304d",
"type": "comment",
"z": "595bb93a55a7385e",
"name": "Reply as per button response",
"info": "Connect with whatsapp Lite (socket client) only",
"x": 400,
"y": 240,
"wires": []
},
{
"id": "45549bbfeb38499a",
"type": "whatsappLink",
"cName": "whatsapp-web",
"name": "Web",
"clientType": "waSocketClient",
"onlineStatus": false,
"loopTime": "5"
}
]

View File

@ -0,0 +1,93 @@
[
{
"id": "595bb93a55a7385e",
"type": "tab",
"label": "Reply to All",
"disabled": false,
"info": "",
"env": []
},
{
"id": "b6f984dbcae75a69",
"type": "chats-out",
"z": "595bb93a55a7385e",
"name": "Chats Out",
"whatsappLink": "45549bbfeb38499a",
"number": "",
"x": 500,
"y": 180,
"wires": []
},
{
"id": "2ea4a9bd3d83e9e4",
"type": "template",
"z": "595bb93a55a7385e",
"name": "",
"field": "payload",
"fieldType": "msg",
"format": "handlebars",
"syntax": "mustache",
"template": "Hi, this is Node-Red reply for your message ( {{payload}} ) !",
"output": "str",
"x": 320,
"y": 180,
"wires": [
[
"b6f984dbcae75a69",
"befa79a6ea6ed85a"
]
]
},
{
"id": "6eeee838055ff52c",
"type": "chats-in",
"z": "595bb93a55a7385e",
"name": "Chats In",
"whatsappLink": "45549bbfeb38499a",
"whatsappLiteevent": "messages.upsert",
"whatsappWebevent": "",
"x": 120,
"y": 180,
"wires": [
[
"2ea4a9bd3d83e9e4"
]
]
},
{
"id": "befa79a6ea6ed85a",
"type": "debug",
"z": "595bb93a55a7385e",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 490,
"y": 280,
"wires": []
},
{
"id": "75123143fa9f3494",
"type": "comment",
"z": "595bb93a55a7385e",
"name": "Simple Ping Pong (Reply to all)",
"info": "",
"x": 350,
"y": 120,
"wires": []
},
{
"id": "45549bbfeb38499a",
"type": "whatsappLink",
"cName": "whatsapp-web",
"name": "Web",
"clientType": "waSocketClient",
"onlineStatus": false,
"loopTime": "5"
}
]

View File

@ -13,28 +13,39 @@ module.exports = function(RED) {
};
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
function webNubmerSeteing(numb){
async function webNubmerSeteing(numb){
numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
numb = `${numb}@g.us`;
return numb
// numb = `${numb}@c.us`;
var numbID = await node.waClient.getNumberId(numb);
if(numbID) {
return `${numbID.user}@${numbID.server}`;
} else {
return `${numb}@g.us`
}
// return numb
}
function socNubmerSeteing(numb){
async function socNubmerSeteing(numb){
if (numb.remoteJid){
return numb.remoteJid;
}
numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
numb = `${numb}@g.us`
return numb
const [result] = await (await node.waClient).onWhatsApp(numb)
if (result?.exists){
console.log(result.exists)
return result.jid
}
return numb = `${numb}@g.us`;
}
async function whatsappMessage(numb , inputMessage){
if (node.waClient.clientType === "waWebClient"){
try {
numb = webNubmerSeteing(numb);
numb = await webNubmerSeteing(numb);
if(typeof inputMessage === "object"){
// inputMessage = new Buttons(inputMessage.text, inputMessage.buttons, "text" ,inputMessage.footer)
let myBtn = new Buttons('Button body',[{body:'bt1'},{body:'bt2'},{body:'bt3'}],'title','footer');
console.log(myBtn)
inputMessage = new Buttons(inputMessage.text, inputMessage.buttons, "text" ,inputMessage.footer);
node.waClient.sendMessage(numb, inputMessage);
inputMessage = myBtn
}
node.waClient.sendMessage(numb, inputMessage);
}
@ -45,14 +56,14 @@ module.exports = function(RED) {
else if (node.waClient.clientType === "waSocketClient"){
try {
let client = await node.waClient;
numb = socNubmerSeteing(numb)
numb = await socNubmerSeteing(numb)
if (typeof inputMessage ==="string"){
inputMessage = {text : inputMessage};
}
const msgStatus = await client.sendMessage(numb, inputMessage);
}
catch(e) {
node.error(`Error Sending Msg: ${e}`);
node.error(`Error Sending Msg:: ${e}`);
}
}
else {
@ -68,12 +79,12 @@ module.exports = function(RED) {
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
try {
if (node.waClient.clientType === "waWebClient"){
numb = webNubmerSeteing(node.number)
numb = await webNubmerSeteing(node.number)
var myMessage = new MessageMedia('image/png', whatsappImageBase64, null, null);
node.waClient.sendMessage(numb, myMessage, {caption : whatsappCaption || "Image from Node-Red"});
}
else {
numb = socNubmerSeteing(node.number)
numb = await socNubmerSeteing(node.number)
const imageMessage = {
text: whatsappCaption,
footer: null,
@ -113,7 +124,10 @@ module.exports = function(RED) {
delay(2000)
}
}
} else {
} else if(message.key.remoteJid){
whatsappMessage(message.key, message.payload)
}
else {
SetStatus("No number","red");
setTimeout(()=>{
SetStatus('Connected','green');
@ -121,8 +135,6 @@ module.exports = function(RED) {
}
});
//whatsapp Status Parameters----
if (node.waClient.clientType === "waWebClient"){
node.waClient.on('qr', (qr) => {
@ -171,6 +183,7 @@ module.exports = function(RED) {
}
}
RED.nodes.registerType("group-out", WhatsappGroupOut);
}

View File

@ -1,6 +1,6 @@
{
"name": "node-red-contrib-whatsapp-link",
"version": "0.1.35",
"version": "0.1.36",
"description": "Node to send and receive whatsapp messages in groups and chats. | No third party APIs",
"repository": {
"type": "git",

View File

@ -4,7 +4,9 @@
defaults: {
cName : {value:"whatsapp-web",required:true},
name : {value : "Web"},
clientType: {}
clientType: {},
onlineStatus : {value : true},
loopTime : {value : 5, validate:RED.validators.number()}
},
label: function() {
return this.clientType;
@ -15,23 +17,35 @@
{
value: "Select Client Type",
options: [
{ value: "waWebClient", label: "Whatsapp Web"},
{ value: "waSocketClient", label: "Whatsapp Lite"},
{ value: "waWebClient", label: "Whatsapp Web"},
]
}
]
})
});
}
});
</script>
<script type="text/html" data-template-name="whatsappLink">
<div>
<label for="node-config-input-client" ><i class="fa fa-cog"></i> Select type of Whatsapp Client : </label>
<input type="text" id="node-config-input-clientType">
<label ><i class="fa fa-cog"></i> Whatsapp Client :
<input type="text" id="node-config-input-clientType" style="width:40%;">
<input type="checkbox" id="node-config-input-onlineStatus">
</label>
</div>
<br>
<div class="form-tips">
<p> All done here just <b>Select the type of Whatsapp Client</b> and proceed.</p>
<p> All done here just Select the type of Whatsapp Client and proceed.</p>
<p> <b>Checkbox On </b> : Shows Online.</p>
<p> <b>Checkbox Off </b> : Shows last seen (As per main device).</p>
<p> To recive push notification on main device, Turn Checkbox Off.</p>
</div>
<br>
<div>
<label ><i class="fa fa-cog"></i> Ping Whatsapp to avoid sleep every :
<input type="text" placeholder="05" id="node-config-input-loopTime" style="width: 15%;"> hr.
</label>
</div>
</script>

View File

@ -12,6 +12,10 @@ module.exports = function(RED) {
RED.nodes.createNode(this,n);
var WAnode = this;
var clientType = n.clientType;
var loopTime = n.loopTime;
loopTime = loopTime + Math.random();
loopTime = loopTime * 60 * 60 * 1000;
var onlineStatus = n.onlineStatus;
var whatsappConnectionStatus;
var client
@ -40,7 +44,20 @@ module.exports = function(RED) {
};
client = WAConnect();
WAnode.connectionSetupID = setInterval(connectionSetup, 10000);
async function pressenceUpdate(OLS){
try {
if (!OLS){
await client.sendPresenceUnavailable();
WAnode.log(`Whatsapp marked as Offline`)
} else {
await client.sendPresenceAvailable();
}
} catch (e){
WAnode.error("Error at pressence : " + e)
}
}
function WAClose(){
try {
client.destroy();
@ -49,12 +66,12 @@ module.exports = function(RED) {
WAnode.err(`Error : Too many instructions! Try again.`)
}
};
var WARestart = function(){
WAClose();
WAConnect();
}
async function connectionSetup(){
try {
whatsappConnectionStatus = await client.getState();
@ -69,7 +86,7 @@ module.exports = function(RED) {
WAnode.log(`Error : Waiting for Initializion...`);
}
};
//QR-Code on Terminal and Ready Status.
client.on("qr", (qr)=>{
clearInterval(WAnode.connectionSetupID);
@ -81,6 +98,7 @@ module.exports = function(RED) {
});
client.on("ready", ()=>{
WAnode.log(`Status : Whatsapp Connected`);
pressenceUpdate(onlineStatus);
});
//Whatsapp-Link Test Features (For Status and Testing Only.)
@ -130,7 +148,7 @@ Participants : ${chat.groupMetadata.size}`
logger:pino({level: "silent"}),
auth : state,
browser: ["Node-RED", "Chrome", "4.0.0"],
markOnlineOnConnect: true,
markOnlineOnConnect: onlineStatus,
patchMessageBeforeSending: (message) => {
const requiresPatch = !!(
message.buttonsMessage || message.templateMessage || message.listMessage
@ -153,8 +171,6 @@ Participants : ${chat.groupMetadata.size}`
})
socketClient.ev.on('creds.update', saveCreds);
console.log(socketClient)
// socketClient.setMaxListeners(0);
socketClient.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update
@ -180,21 +196,51 @@ Participants : ${chat.groupMetadata.size}`
FS.rmSync(whatsappLinkDirSocket, {recursive : true, force: true})
connectSocketClient()
} else {
WAnode.error(lastDisconnect?.error)
WAnode.log("Error : " + lastDisconnect?.error)
}
}
}
})
})
return socketClient
};
client = connectSocketClient();
client.onlineStatus = onlineStatus;
client.clientType = clientType;
client.clientStartFunction = connectSocketClient;
WAnode.client = client
};
async function loopStatusUpdate(){
try {
if (clientType === "waSocketClient"){
let myClient = await WAnode.client;
let id = myClient.user.id;
await myClient.sendPresenceUpdate("available", id)
if (!onlineStatus) {
setTimeout(()=> {
myClient.sendPresenceUpdate("unavailable", id)
},17000)
};
}
else {
await WAnode.client.sendPresenceAvailable();
if (!onlineStatus) {
setTimeout(()=> {
WAnode.client.sendPresenceUnavailable();
},17000)
};
}}
catch(e){
WAnode.error("Error in whatsapp Ping.")
}
}
var loopStatusUpdateID = setInterval(()=> {
loopStatusUpdate();
}, loopTime)
this.on('close', (removed, done)=>{
clearInterval(loopStatusUpdateID);
if(removed){
if(clientType === "waWebClient"){
clearInterval(WAnode.connectionSetupID);