Friday, January 23, 2015

Using whatsapp for home automation - Something real

Last time we saw how to start interpreting whatsapp messages using a simple parser written in Python.

What we did was implementing just a small interaction with our RPi and nothing more. Surely it wasn't a real home automation.

Now it's time to try something closer to that definition. I will keep quite simple, but the concepts are valid for more complex situations too.

Anyway I will just take into account only low-level automation. What I mean is that communication protocols like X10, 1-wire, Modbus, ZigBee and so on will not be used, at least for now.

Maybe in a future I could write a post about these, but do not take this as a fact. It just could happen one day...

To make some automation we need two types of things than can be connected to a Raspberry Pi: sensors and actuators.

Sensors could be something like:
  • switch
  • temperature sensor
  • pressure sensor
  • humidity sensor
  • light level sensor
  • microphone
  • current flow
and so on. Every electrical device that can provide a signal can be used as a sensor. It's just a matter of signal compatibility (more on this later).

About actuators there could be
  • relays
  • remote controlled light
  • remote controlled power plug
  • ir transmitter
  • electromagnet
  • speaker
  • led
much of these could be thinked of as just electromagnets, as many thing can be controlled switching on or off the main power with a simple relay (i.e.: a switch controlled by an electromagnet).

As for the sensors, we need to make all the signals compatible. Remember that a RPi has several digital I/O with 3.3V levels, so outgoing signals have to be increased somehow if You need to control something with different level, such as a 5V releay.

Incoming signals may need to be modified too. A switch must send 0-3.3V to the RPi. Analog devices should convert their signals to a digital form and send it somehow to the RPi (good choiche could be using I2C interface).

By connecting sensors and actuators, using Whatsapp messages we could think to do something like the following:
  • ask RPi if we turned off the light (and RPi will answer if the light is on or off)
  • tell RPi to heat the house at a specified time
  • inform us if the door has been opened and at the same time switch on the light (or turn on an alarm)
  • if inside temperature is above 30°C turn on air conditioning
  • ask RPi to start watering the plants and stop after 3 minutes

These are just examples, some more complex and some less, but all could be managed the same way.
Let's start with a relay controlling a lamp. Look at the following scheme:


The relay is a 5V device, so we need to convert the 3.3V of RPi GPIO. 

Remember that there are several add-on boards for RPi that can do the voltage correction without any other component and some of those boards have relays mounted on them. I'm showing you how to accomplish this without any add-on.

As the relay is a 5V type we will connect one pin to RPi 5V from the header (you can find a good pinout diagram here). The diode (could be a 1N4001 or 1N4148) is used for protection and must be present or the RPi could be damaged.
Resistor and transistor are used to switch on/off the relay using just th 3.3V from a GPIO pin. When GPIO is set to 1 (3.3V output) the transistor conduct and current can flow from 5V through the relay (and the transistor) to the GND, switching the relay position.

You need to take care of one problem that could happen here: the more relays you are switching on, the more current will be drawned from the 5V RPi header, so the power has to be high enough to drive all of them!

I will implement a way to switch on/off a light with a Whatsapp message like: turn on the light, but could also be turn the light on (the same for switching off).

To use GPIO pins with Python we need to use RPi-GPIO library. At the beginning of the parser script add the following lines:

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)

this will load the library and set it's use (refer to the library documentation for differences between the usage modes).

Assuming that the relay is connected to GPIO18 (header pin 12, set as output in the section above) we can create a function like the following:

def SetLight(msg):
    if " on" in msg:
        GPIO.output(12, GPIO.HIGH)
        Answer("The light has been turned on")
    elif " off" in msg:
        GPIO.output(12, GPIO.LOW)
        Answer("The light has been turned off")
    else Answer("Cannot understand what you wish to do with the light!")
    return

and in the parser section we will add the following:

            elif received[:6]=="switch" and "light" in received: SetLight(received)

In the parser we are checking if the text starts with the word switch and if the word light is inside the message at the same time (in any place), then we pass the received message to the function.

Inside that function we just check if one of the word on or off are inside the text and act consequently. If none of those words is found we reply with an error, otherwise an acknowledge message is sent (if you do not want that message you can leave it off, but remember to delete the text file of the received Whatsapp text!).

Note that if you send something like turn the light on or off, the script thinks you are asking for turning on, because the function test for the word on and only if this is not found it will check for the word off.

Of course you could connect the relay to something else and change the checked words to match your setup and add more relays and commands.
Now let's check a switch status:


With this connection the GPIO pin is read as 1 when the switch is in the position above. When it changes the position we will read 0.

To avoid problems we have to use a pull-up resistor connected to the GPIO to keep it on when "floating" (not connected to a power line or to GND).
RPi has internal pull-up and pull-down resistors already connected. They just have to be enabled to be used.

Let's assume that the switch is connected to GPIO17 (header pin 11). First of all we must specify that it's an input pin and we wish to enable the pull-up resistor, so put this under the pin 12 definition:

GPIO.setup(11, GPIO.IN, pull_up_down=GPIO.PUD_UP)

We will use this switch to check if the door is open or close. So we could send the RPi a message like is the door open? or what is the door status?

Let's use this function (you may need to swap the answers depending on your setup):

def DoorStatus():
    if GPIO.input(11):
        print('The door is close')
    else:
        print('The door is open!')
    return

and in the parser add this row:

            elif received[:4]=="door": DoorStatus()

so every message containing the word door will trigger this function.

Let's go even further. Nice to have an answer from RPi when asking, but it's not so useful to know if the door has been opened only when asking for this... RPi should inform us immediately when the door opens, so we can take some action.

After the import section add this line:

dooropen=0

and at the end of the script add the following rows:

    if dooropen==0 and GPIO.input(11)==0:
        dooropen=1
        Answer("Warning! The door has been opened right now!")
    if GPIO.input(11): dooropen=0

The variable dooropen is used to know if the message has already been sent in case of an opening, so if the message has not been sent (dooropen is 0) and the door is open we just send a Whatsapp message to our smartphone and set the message as "sent" (dooropen=1).
When the door is closed, we just put dooropen to 0, so the next time someone opens the door a new message can be sent again.

That's all. The parser could be greatly improved, but it's enough for starting with Raspberry Pi, Whatsapp and home automation. If you have some question, just ask in the comment section.

8 comments:

  1. where should I put these codes ?

    ReplyDelete
    Replies
    1. These codes should be used inside the parser. Take a look at the previous posts for more info.

      Delete
    2. Hello Sir,
      In your above code,GPIOs accessing portion is good, but it won't be possible to send message via yowsup using your code, since no connection between yowsup and your hardware interface is present.

      Delete
  2. Hi, Mr Carlo.

    I am using something similar as you write in this article, a moving detector and on-off sensor in my door.
    I have a simple problem with whatsapp and the GPIO pins. I think. When I debug the program everything is ok, it detects every interruption, but the function Answer does not send me a message. but it runs the function completly.
    When I simulate the sensors with a switches, It has a response and send me the correct message (So, I verify that everything is ok).

    I am not sure What is wrong, I assume, maybe a conflict or problem between GPIO pins and the yowsup module.
    After the detection as you posted, I use the same Answer Function, but I am not receiving a msg.
    Evenmore, I am starting to run scripts separately. using os.system(one code Answer), but the same result.

    did you have those kind of problems?, any idea how to solve this.

    I appreciate your help.


    ReplyDelete
    Replies
    1. This is quite strange... The only thing I can think of is timing. If the moving detector switches too often, maybe Yowsup could have some problems, but it's just a theory.
      As you already split the scripts, you could try to use yowsup-cli to send the message and see if this works. This is the script officially supplied with Yowsup and maybe it could be more reliable...
      As far as I know (remember that Yowsup is not made by me, I just used it, so I could be wrong) there should be no connection between Yowsup and GPIO pins, so I can't see why this could happen.
      Anyway I had similar issues (non related to GPIO) and sometimes messages just "disappeared". That's why I'm not using Yowsup anymore.

      Delete
  3. Thank you.
    I test the number, and it is ok, I used another SIM numbers, and works. the problem is with my number, but that is weird. but it is important a delay in order to have a good response (time.sleep(1)).
    Do you meant, send a message from terminal with yowsup-cli?. that works. or run this yowsup-cli inside a python script?.
    Are you using Telegram?.

    ReplyDelete
    Replies
    1. I meant using yowsup-cli inside python. Anyway if changing SIM works that should be enough (even if I can't really think why this happens!).

      I do not use Telegram. For messaging just Whatsapp and for RPi notifications now I'm using Pushover.

      Delete