yowsup - Integrating sending and receiving

18,229
@ProtocolEntityCallback("send_message")
    def sendMessage(self, destination, message, messageProtocolEntity):
        outgoingMessageProtocolEntity = TextMessageProtocolEntity(
        message,
        to = destination + "@s.whatsapp.net")
        self.toLower(outgoingMessageProtocolEntity)

In the avove code sendMessage to be called, protocolEntity.getTag() == "send_message" has to be True. You don't need it to send message.

layer.py

from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
from yowsup.layers.protocol_messages.protocolentities import TextMessageProtocolEntity
from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity
from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity
from yowsup.layers.protocol_presence.protocolentities import PresenceProtocolEntity
import threading
import logging

logger = logging.getLogger(__name__)
recv_msg = []

class EchoLayer(YowInterfaceLayer):

    def __init__(self):
        super(EchoLayer, self).__init__()
        self.ackQueue = []
        self.lock = threading.Condition()

@ProtocolEntityCallback("message")
def onMessage(self, messageProtocolEntity):
    if messageProtocolEntity.getType() == 'text':
        recv_msg.append((messageProtocolEntity.getFrom(),messageProtocolEntity.getBody()))

    #send receipt otherwise we keep receiving the same message over and over
    receipt = OutgoingReceiptProtocolEntity(messageProtocolEntity.getId(), messageProtocolEntity.getFrom())
    self.toLower(receipt)

    @ProtocolEntityCallback("receipt")
    def onReceipt(self, entity):
        ack = OutgoingAckProtocolEntity(entity.getId(), "receipt", "delivery")
        self.toLower(ack)

    # List of (jid, message) tuples
    PROP_MESSAGES = "org.openwhatsapp.yowsup.prop.sendclient.queue"

    @ProtocolEntityCallback("success")
    def onSuccess(self, successProtocolEntity):
        self.lock.acquire()
        for target in self.getProp(self.__class__.PROP_MESSAGES, []):
            phone, message = target
            if '@' in phone:
                messageEntity = TextMessageProtocolEntity(message, to = phone)
            elif '-' in phone:
                messageEntity = TextMessageProtocolEntity(message, to = "%[email protected]" % phone)
            else:
                messageEntity = TextMessageProtocolEntity(message, to = "%[email protected]" % phone)
            self.ackQueue.append(messageEntity.getId())
            self.toLower(messageEntity)
        self.lock.release()

    @ProtocolEntityCallback("ack")
    def onAck(self, entity):
        self.lock.acquire()

        if entity.getId() in self.ackQueue:
            self.ackQueue.pop(self.ackQueue.index(entity.getId()))

        if not len(self.ackQueue):
            self.lock.release()
            logger.info("Message sent")
            raise KeyboardInterrupt()

        self.lock.release()

To send message define a function send_message in the stack run.py. You can also import run.py and use it's function from other script.

from layer import EchoLayer, recv_msg
CREDENTIALS = ("phone", "pwd")
def send_message(destination, message):

    ''' 
    destination is <phone number> without '+'
    and with country code of type string,
    message is string
    e.g send_message('11133434343','hello')
    '''
    messages = [(destination, message)]
    layers = (EchoLayer,
              (YowAuthenticationProtocolLayer,
               YowMessagesProtocolLayer,
               YowReceiptProtocolLayer,
               YowAckProtocolLayer,
               YowPresenceProtocolLayer)
              ) + YOWSUP_CORE_LAYERS
    stack = YowStack(layers)
    stack.setProp(EchoLayer.PROP_MESSAGES, messages)
    stack.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True)
    # Setting credentials
    stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)

    # WhatsApp server address
    stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
    stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)              
    stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())

    # Sending connecting signal
    stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
    try:
        # Program main loop
        stack.loop()
    except AuthError as e:
        print('Authentication error %s' % e.message)
        sys.exit(1)

def recv_message():
    layers = (  EchoLayer,
                (YowAuthenticationProtocolLayer, YowMessagesProtocolLayer,
                YowReceiptProtocolLayer, YowAckProtocolLayer,
                YowPresenceProtocolLayer)
             ) + YOWSUP_CORE_LAYERS

    stack = YowStack(layers)
    # Setting credentials
    stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)

    # WhatsApp server address
    stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
    stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
    stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())

    # Sending connecting signal
    stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
    try:
        # Program main loop
        stack.loop()
    except AuthError as e:
        print('Authentication error %s' % e.message)
        sys.exit(1)

if __name__ == '__main__':
    if len(sys.argv) == 1:
        print('%s send number message\nrecv\n' % sys.argv[0])
        sys.exit(1)
    if sys.argv[1] == 'send':
        try:
            send_message(sys.argv[2],sys.argv[3])
        except KeyboardInterrupt:
            print('closing')
            sys.exit(0)
    if sys.argv[1] == 'recv':
        try:
            recv_message()
        except KeyboardInterrupt:
            print('closing')
            sys.exit(0)
        for m in recv_msg:
            print('From %s:\n%s\n' % m)

Now you can send message by calling send_message('1234567890','Howdy') and recieve message by calling recv_message().

Share:
18,229
Admin
Author by

Admin

Updated on June 29, 2022

Comments

  • Admin
    Admin almost 2 years

    Background:

    I would like to integrate yowsup to my home automation project. I have seen a simple sample on how to receive messages and after some minor changes it is working fine.

    Issue:

    My problem starts when it comes to integrate the send message feature. Those are the two files I am using:

    run.py

    from layer import EchoLayer
    
    from yowsup.layers.auth import YowAuthenticationProtocolLayer
    from yowsup.layers.protocol_messages import YowMessagesProtocolLayer
    from yowsup.layers.protocol_receipts import YowReceiptProtocolLayer
    from yowsup.layers.protocol_acks import YowAckProtocolLayer
    from yowsup.layers.protocol_presence import YowPresenceProtocolLayer
    from yowsup.layers.network import YowNetworkLayer
    from yowsup.layers.coder import YowCoderLayer
    from yowsup.common import YowConstants
    from yowsup.layers import YowLayerEvent
    from yowsup.stacks import YowStack, YOWSUP_CORE_LAYERS
    from yowsup import env
    
    
    CREDENTIALS = ("phone", "pwd")
    
    if __name__ == "__main__":
    
        layers = (
            EchoLayer,
            (YowAuthenticationProtocolLayer, YowMessagesProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer, YowPresenceProtocolLayer)
        ) + YOWSUP_CORE_LAYERS
    
        stack = YowStack(layers)
        # Setting credentials
        stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)
    
        # WhatsApp server address
        stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
        stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)              
        stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())
    
        # Sending connecting signal
        stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
    
        # Program main loop
        stack.loop()
    

    layer.py

    from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
    from yowsup.layers.protocol_messages.protocolentities import TextMessageProtocolEntity
    from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity
    from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity
    from yowsup.layers.protocol_presence.protocolentities import PresenceProtocolEntity
    import threading
    import logging
    
    logger = logging.getLogger(__name__)
    
    class EchoLayer(YowInterfaceLayer):
    
        @ProtocolEntityCallback("message")
        def onMessage(self, messageProtocolEntity):
            #send receipt otherwise we keep receiving the same message over and over
            print str(messageProtocolEntity.getFrom()) + ' - ' + str(messageProtocolEntity.getBody())
            receipt = OutgoingReceiptProtocolEntity(messageProtocolEntity.getId(), messageProtocolEntity.getFrom())
            self.toLower(receipt)
    
        @ProtocolEntityCallback("send_message")
        def sendMessage(self, destination, message, messageProtocolEntity):
            outgoingMessageProtocolEntity = TextMessageProtocolEntity(
            message,
            to = destination + "@s.whatsapp.net")
            self.toLower(outgoingMessageProtocolEntity)
    
    
        @ProtocolEntityCallback("receipt")
        def onReceipt(self, entity):
            ack = OutgoingAckProtocolEntity(entity.getId(), "receipt", "delivery")
            self.toLower(ack)
    
        # List of (jid, message) tuples
        PROP_MESSAGES = "org.openwhatsapp.yowsup.prop.sendclient.queue"
    
        def __init__(self):
            super(EchoLayer, self).__init__()
            self.ackQueue = []
            self.lock = threading.Condition()
    
        @ProtocolEntityCallback("success")
        def onSuccess(self, successProtocolEntity):
            self.lock.acquire()
            for target in self.getProp(self.__class__.PROP_MESSAGES, []):
                phone, message = target
                if '@' in phone:
                    messageEntity = TextMessageProtocolEntity(message, to = phone)
                elif '-' in phone:
                    messageEntity = TextMessageProtocolEntity(message, to = "%[email protected]" % phone)
                else:
                    messageEntity = TextMessageProtocolEntity(message, to = "%[email protected]" % phone)
                self.ackQueue.append(messageEntity.getId())
                self.toLower(messageEntity)
            self.lock.release()
    
        @ProtocolEntityCallback("ack")
        def onAck(self, entity):
            self.lock.acquire()
    
            if entity.getId() in self.ackQueue:
                self.ackQueue.pop(self.ackQueue.index(entity.getId()))
    
            if not len(self.ackQueue):
                logger.info("Message sent")
                #raise KeyboardInterrupt()
    
            self.lock.release()
    

    Questions:

    • Where am I supposed to call the send_message method, so I can send messages wherever I need it?
    • Is there a regular event (triggering every second or something) which I could use to send my messages?