andytwoods

engineer psychologist

Pizero arty alexa-powered sunblind controller

Nov. 4, 2020

art servo pizero alexa
piart.jpg

I need to be careful with sunburn, so we installed an electronic sun-blind that extends out from the house to cover part of our garden. I was excited to hear from the people who we bought the sun-blind from, that we could control it with Alexa. It was not mentioned we would need to buy a £250 device to link the blind with Alexa. I decided to build my own device for £30.

Ingredients

  • £10 cheap clone of the 'dumb' remote we were given to control the device from ebay.
  • £10 raspberry pi-zero wifi
  • £5 4-channel relay (Kuman 4 Channel DC 5V Relay Module for ArduinoIDE Raspberry Pi DSP AVR PIC ARM K49)
  • £5 photo-frame (2 for 1!)
  • A mounting-kit to attach the devices to the back of the photo-frame.

This was straight a straight forward project and just required connecting up simple circuitry to control the buttons on the remote (that I took to pieces and soldered wires onto, to allow me to control its push buttons via the pizero).

I used Flask-Ask on another pizero (see my pi-parking project) that in turn contacted this pizero to control the relays which in turn controlled the sunblinds. I used Quart, not Flask, because I needed to be able to stop the blinds rolling out after 0-10 seconds (specified by the Alexa command), which required Async to allow the app to immediately reply to the Alexa backend, and then, at a later time, stop the blinds from moving. I guess I could have used Celery-Beat to achieve the same goal, but using aync was the simpler option.

I'll write another blog on setting things up in the Alexa-console backend. It was tricky and not that intuitive. Despite that, it was a far better experience than I had setting up a similar project (pi-parking) but with google-assistant. I perhaps spent an hour setting up the Alexa backend here, compared to 4, on that other project.

import asyncio
import platform

from quart import Quart, Response
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

pins = [18, 17, 15, 14]

blinds_stop = pins[0]
blinds_out = pins[1]
blinds_in = pins[2]

GPIO.setup(pins, GPIO.OUT)

WINDOWS = platform.system() == 'Windows'

app = Quart(__name__)

config = {}

app.config.from_mapping(config)

port = 5000

locked = False


@app.route('/all_off')
async def all_off():
    for _pin in pins:
        GPIO.output(_pin, GPIO.HIGH)
    return 'all off'

for _pin in pins:
    GPIO.output(_pin, GPIO.HIGH)


async def blinds_action(blind):
    GPIO.output(blind, GPIO.LOW)
    time.sleep(1)
    GPIO.output(blind, GPIO.HIGH)


async def stop_later(s):
    print('here')
    global locked
    if not locked:
        time.sleep(s)
        locked = False
        await stop()


@app.route('/out', defaults={'s': None})
@app.route('/out/<int:s>')
async def out_for(s=None):
    await blinds_action(blinds_out)
    if s:
        asyncio.ensure_future(stop_later(s))
    return 'out'


@app.route('/in', defaults={'s': None})
@app.route('/in/<int:s>')
async def in_for(s=None):
    await blinds_action(blinds_in)
    if s:
        asyncio.ensure_future(stop_later(s))
    return 'in'


@app.route('/stop')
async def stop():
    await blinds_action(blinds_stop)
    return Response('stop')


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=port)

I have got a lot of joy out of this project. I've a spare photo-frame and am considering what to do for my next arty pi project :)

Return to blog