Google Home + Raspberry Pi Power Strip

41,150

46

70

About: I'm a maker, programmer, and designer. I love music, games, and simple design.

UPDATE #2: IFTTT changes:

My existing IFTTT commands through the maker channel are still working, but they've changed the naming structure since I made this guide. New commands still use the Google Assistant trigger, but the web requests are now handled by the "Webhooks" action.

UPDATE #1: Starter Application Now Available!

Hello World!

Now that the Google Home is out, there are lots of people wondering how to use it to control their existing Arduino or Raspberry Pi smart devices. Now that I've got my setup working, I thought I would share my fairly simple setup with you.

While I am currently using a Raspberry Pi Zero to control a five outlet power strip, This guide is more general. It will walk you through how to use any Raspberry Pi device to control an electronic relay, using Node.js and the IFTTT web services.

Check out a video of the device in action, or scroll to the final step, where I have it embedded!

https://www.youtube.com/watch?v=mCTjZTCaTzM

Step 1: What You'll Need

At the very least, you will need:

And the rest is software. If you are totally new to Raspberry Pi, be aware that you may need some additional hardware like usb cables or wifi chips in order to get up and running.

Step 2: On-Board Software Setup

So, to make this guide as user-friendly as possible, I'm going to include some links that you power-users might find excessive.

TLDR in advance: set up your raspberry pi on WiFi or Ethernet (preferably WiFi) and configure your router so that you have a server available externally. You'll use raspberry-gpio-python to control the relay.

For newer hobbyists, you will start out by setting up your raspberry pi.

You will want to get your raspberry pi set up on your local WiFi.

I'll be working in Node.js, so you will want to upgrade to the latest version of Node.

Configure the router so that port 80 redirects to your raspberry Pi's MAC address. (Sorry, this will depend on what router you're using, and there isn't really a universal guide)

I prefer using SSH to connect to my raspberry pi.

Plenty of things can go wrong in this process while you're starting out. Stay patient, and google things. The community is very supportive, and the odds are someone else has had your problem before!

Step 3: Make a Circuit

So, there are lots of guides on getting started with relays on the Rasberry Pi. I mostly used Youtube tutorials like this one to get started.

Basically, you will need to provide power from your Raspberry Pi's 5v out pin, and choose which control pins you want to use to send the on/off signal to trigger the relay.

Using the above image, I recommend using the yellow pins for whichever model you use.

Step 4: Create Your Server

Starter application now available!

Vist https://github.com/krpeacock/google_home_starter to download a starter application for this project, and follow the README to get it configured and running on your own device.

You can also check out my more-fleshed-out React project at https://github.com/krpeacock/power_strip/tree/strip if you are interested in seeing a slightly more complex version of the project

The main step is to build an Node + Express server that is able to handle POST requests.

In my code, it looks like this:

app.post('/api/switches/:id', function(req, res){  

  var foundSwitch = getSwitch(req.params.id);  

  foundSwitch.toggle();  

  saveState();  

  console.log("postSwitch "+JSON.stringify(foundSwitch));  

  res.json(foundSwitch);

})

I make a post request to /api/switches/:id, where id is written as sw1, sw2, and so on. After identifying the switch, I call a toggle() method to run my Python script and change the state of my relay.

I wrote individual python scripts for off and on functions, specifying which GPIO pin was tied to each switch. for example, sw1_on.py looks like:

import RPi.GPIO as GPIO<br>GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.OUT)

Then, by requiring the Python-shell node module, I can execute the script, using:

<p>const PythonShell = require('python-shell');</p><p>PythonShell.run('./public/python/scripts/sw1_on.py')</p>

Looking back, this is a little bit tricky for a non-developer. I probably will need to throw in some starter code down the road.

Step 5: Connecting to the Google Home

If you've managed to get this far, this information is probably the only reason that you're here. That's fine! this is the cool bit.

You have your server running, and it can control a relay. It is structured so that a POST request can change the state of the relay. Now all you need is to get your Google Home to deliver a POST request to your device. Eventually, you will want to add some authorization so that strangers can't control your devices, but now we just want the request to work.

  1. Go to https://ifttt.com and connect it to your Google account.
  2. Go to https://ifttt.com/create, and click on the +this link.
  3. Search for Google Assistant
  4. Select Google Assistant
  5. Choose "Say a simple phrase" as your trigger
  6. Tell Google what should trigger the action.
    • I prefer to name use the device I want to control, so I said "turn my lamp on"
  7. Designate a response
    • "Turning your lamp on"
  8. Click "Create Trigger" and proceed
  9. Click the +that link
  10. Search for "Webhooks"
  11. Select "Make a web request"

Now, here is the important bit. Identify your IP address (or domain, if you set up that level of abstraction), and enter it into the URL portion. If you followed my the structure in my starter project, it will look like

http://ipaddressgoeshere/API/switches/sw1?password=yourpasswordhere

Set Method to POST

Content Type should be text/plain

Body can be left blank

Create your action and choose Finish.

Step 6: Congrats!

You've done it! Your Google Home now knows how to communicate over HTTP with your smart device.

Since this does a toggle, you can technically keep saying "Turn the lamp on" to turn it on and off. I preferred to add duplicate on and off commands for each of my switches to make everything feel more comfortable.

If you would like to contribute to this guide, or to work with me on building out a starter application, you can also feel free to get in touch! I want to make this process as easy as possible for new hackers.

Share

    Recommendations

    • Arduino Contest 2019

      Arduino Contest 2019
    • Trash to Treasure

      Trash to Treasure
    • Tape Contest

      Tape Contest

    70 Discussions

    0
    None
    ΜάτσαςΑ

    12 days ago

    Thank you for your help! I have a totally different setup, but that webhook guide....helped me a lot!!!

    0
    None
    Abhinav Peddi

    Question 4 months ago

    Don't you think we need port forwarding? because google home cannot send requests to local machines (IP Addresses) right?

    2 answers
    0
    None
    DannyR87Abhinav Peddi

    Answer 3 months ago

    +1. Even after setting up port forwarding I'm having issues (IFTTT constantly errors with ETIMEDOUT). Any thoughts?

    0
    None
    ConorH18DannyR87

    Reply 3 months ago

    yes i had the same issue.
    I used an API tester to give me a debug log of what was wrong, turns out port 8080 worked the best for this and setting my internal IP as a higher number while static to avoid it being taken when the Pi restarts. It is now up and running with no interactions other than with my Google Assistant

    0
    None
    ConorH18

    Question 3 months ago on Step 2

    so Ive tested the .py scrips in the public folder and the npm start runs to listening on port 80
    I have the port forwarded correctly to my pi
    on the IFTTT Aplet however im getting the following
    "Unable to make web request: Error: ETIMEDOUT"

    this is my webhook URL "http:// myPublicIP/ API/ switches/ sw1?password=test&state=on:80" minus the spaces (Obviously)
    my .env
    DEV=FALSE
    PORT=80
    PASS=test
    is there anyone here who has any ideas as to why I am getting this?

    1 answer
    0
    None
    ConorH18ConorH18

    Answer 3 months ago

    Nevermind, I used an API tester to give me a debug log of what was wrong, turns out port 8080 worked the best for this and setting my internal IP as a higher number while static to avoid it being taken when the Pi restarts. thank you for this code it is now up and running with no interactions other than with my Google Assistant

    0
    None
    Call_me_ben

    Question 5 months ago

    Hi Kyle, your tutorial worked out great for me, but I'm still questioning one thing. Would it be possible to integrate a button click rather than a switch seamlessly? Or would the best way be to simply reset a switch to off after an update is detected? I'm fairly new to all of this with limited python knowledge. Thanks in advance

    2 answers
    0
    None
    call_me_kyleCall_me_ben

    Answer 5 months ago

    There are plenty of ways you could make that work! I wanted mine to use a website or use voice control, but you could definitely find some way to get a button to trigger IFTTT. I suspect that most buttons that support Alexa would be good candidates, or you could find a way to do it directly through the Pi.

    Congrats on your build, and I encourage you to push yourself to build your own vision!

    0
    None
    Call_me_bencall_me_kyle

    Reply 5 months ago

    Thank you for the reply, the reason I need it to function as a button is to replace the buttons on a fan remote, but I've started to doubt that it's the best way to automate it. Do you have any other ideas for me? The fan is a 3 speed with a light that dims when you hold the button, but I should be able to bypass that. Or should I try making my own control unit?

    0
    None
    flashback_pa

    Question 6 months ago

    Hey all, really a newbie with node.js, btw installed node and npm, then downloaded your very very interesting project, and then since couple days, knocking my head on the wall trying to understand why it won't work with my setup. The python files works, the light turns on and off, but calling http://ipaddressgoeshere/API/switches/sw1?password... (with obvious values inside) nothing happens except the value: {"id":"sw1","state":"off","name":"Kyle's Lamp"}.
    I can't even understand how to pass on and off parameter to the post...
    Would anybody please save me from autodestruction ? ;)
    Thank you.

    3 answers
    0
    None
    flashback_pacall_me_kyle

    Reply 6 months ago

    Thank you for the quick answer, but nothing changes, all i got is always:
    {"id":"sw1","state":"off","name":"Kyle's Lamp"}
    even calling:
    http://myip:myport/API/switches/sw1?password=mypass&state=on
    What else can i try ?
    Just to say, no error is logged if i use the wrong password...
    Thank you.

    Some infos:
    -20:19:19-[root@raspi6]@ </opt/google_home_starter-master> ;> node -v
    v11.0.0
    -20:19:22-[root@raspi6]@ </opt/google_home_starter-master> ;> npm -v
    6.4.1
    -20:19:28-[root@raspi6]@ </opt/google_home_starter-master> ;> npm start
    > google_home_controller@1.0.0 start /opt/google_home_starter-master
    > node app.js
    Listening on port 8901

    0
    None
    flashback_paflashback_pa

    Reply 6 months ago

    I just decided to play with Postman as somebody wrote down...and i got wrong password message now, and with the right one this happened:

    TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
    at maybeCallback (fs.js:136:9)
    at Object.writeFile (fs.js:1174:14)
    at saveState (/opt/google_home_starter-master/app.js:81:6)
    at /opt/google_home_starter-master/app.js:119:5
    at Layer.handle [as handle_request] (/opt/google_home_starter-master/node_modules/express/lib/router/layer.js:95:5)
    at next (/opt/google_home_starter-master/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/opt/google_home_starter-master/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/opt/google_home_starter-master/node_modules/express/lib/router/layer.js:95:5)
    at /opt/google_home_starter-master/node_modules/express/lib/router/index.js:281:22
    at param (/opt/google_home_starter-master/node_modules/express/lib/router/index.js:354:14)

    But the light turns ON !
    But the raspberry is stuck and i need to powercycle it....

    0
    None
    Jordan76149

    Question 8 months ago

    hey guys, need some help. the readme says you have to edit the .env file with the port and other data. but I can't seem to find it anywhere, am I missing something?

    3 answers
    0
    None
    call_me_kyleJordan76149

    Answer 8 months ago

    The .env file isn't tracked in Git in order to let you keep other people from seeing your configuration details.

    You'll need to add a file yourself and name it .env using the filesystem, running 'touch .env' in your terminal, or some other method. Hope this helps!

    0
    None
    Jordan76149call_me_kyle

    Reply 8 months ago

    Great thanks Kyle, also, it all seems set up. The GPIO pin starts HIGH when i boot up, then the first time I run the URL it switches off. Then after that nothing... also in the terminal after running npm start - "listening on port undefined"

    I think my .env file is incorrect.

    Sorry I'm new to this

    0
    None
    call_me_kyleJordan76149

    Reply 8 months ago

    Sorry for the delayed response. You need to define the port in the .env file. Add a new line that looks like:

    PORT=3000

    to the .env file and try running it again.

    0
    None
    JD_DEV

    Question 8 months ago

    Hi, need some help. I followed the steps as per your tutorial but i am stuck in the web request part. I used Postman to POST the URL but getting following errors;

    TypeError [ERR_INVALID_CALLBACK]: Callback must be a function at maybeCallback (fs.js:127:9) at Object.writeFile (fs.js:1123:14) at saveState (/home/pi/app.js:91:6) at /home/pi/app.js:130:5 at Layer.handle [as handle_request] (/home/pi/node_modules/express/lib/router/layer.js:95:5) at next (/home/pi/node_modules/express/lib/router/route.js:137:13) at Route.dispatch (/home/pi/node_modules/express/lib/router/route.js:112:3) at Layer.handle [as handle_request] (/home/pi/node_modules/express/lib/router/layer.js:95:5) at /home/pi/node_modules/express/lib/router/index.js:281:22 at param (/home/pi/node_modules/express/lib/router/index.js:354:14)

    When i am running the npm server, it is listening to port 8000 and if i am opening the web request in the browser, it is displaying the following message;

    {"id":"sw1","state":"off","name":"Kyle's Lamp"}

    Also the ON/OFF python scripts are running correctly from the command line.

    My node version is v10.9.0

    I am new to programming. I am stuck to this problem for sometime, tried to google but didnt find the solution. Please help.

    Thanks,

    JD

    1 answer
    0
    None
    call_me_kyleJD_DEV

    Answer 8 months ago

    That's a deeper issue than I can fix just by visualizing it. Shoot me a direct message, and I could probably take a look at a zipped version of your app or if you've forked the starter repo

    0
    None
    Jpkrogam

    1 year ago

    Great tutorial. I got the basic one working but couldn't get the power strip web page to work. It loads up with just a grey background. Looks like the index.html refers to a js file that doesnt exist : 'bundle.js'. I changed it to refer to index.js but then it keeps erroring out on the "import React from 'react'" line. Tried a bunch of stuff with packages but couldnt figure it out. If someone got it working let me know what worked for you :)