Table of Contents

Controlling our entrance gate from android app

Okay so, there is a “little home project” I would like to quickly setup here: we are currently using remote controls to open/close our entrance gate [just as most people do!]. But now I'm thinking I could try to push this a bit further and implement a custom mechanism to control the opening of the gate from the Internet éh éh éh [I know: not the most secured thing to do on earth, but we'll get back to that point another day].

If I can do that, then I could create a minimal android app that I could install on our family phones to open/close the gate with a simple button press! That would be great [and fun at the same time]… So where should we start ?

Setting up the raspberry device for ssh remote access

First thing first: I have a couple of spare raspberry pi units here, so I'll be using one of those as the “controller/server” in this project. Thus, I need to ensure I can access it remotely through ssh for quick configuration.

The default password for the pi user is “raspberry” in raspbian

Preparing a minimal test circuit with a relay

To be able to test the raspberry with a relay we need a minimal test circuit, let prepare that.

okay, so the circuit itself is pretty simple, with just one battery, one LED, one resistor and cables:

circuit_disconnected.jpg

circuit_connected.jpg

But now comes the funny part: how am I going to insert a relay in there (note: I only have a “naked” SRD-05VDC-SL-C component for the moment lol)

⇒ And I finally found some kind of datasheet for that component, it was not very clear but I could finally figure out how it works, and updated my little test circuit to include the relay, and this seems to work as expected:

relay_disabled.jpg

relay_enabled.jpg

As one can see on the picture above, I'm using the battery itself as power source for the relay… This is a 4.5V battery, but on raspberry I will only get 3.3V… let's hope this will still work!

Plugging test circuit on raspberry

And in fact when connected to the raspberry over ssh, we can use the command “pinout” to get a very useful mapping of the GPIO ports.

connected_to_raspberry.jpg

Good, now it's time to build a small program to try this thing :-)!

Test python program

We have python 2.7.9 with pip 1.5.6 installed on the raspberry. I'm not quite sure I have the package “RPi.GPIO” installed by default, but anyway, let's just try the following minimal test program to see how this behaves first:

import RPi.GPIO as GPIO
from time import sleep
relay_pin = 
GPIO.setmode(GPIO.BCM)
GPIO.setup(relay_pin, GPIO.OUT)
GPIO.output(relay_pin, 1)
try:
    while True:
        GPIO.output(relay_pin, 0)
        sleep(5)
        GPIO.output(relay_pin, 1)
        sleep(5)
except KeyboardInterrupt:
  pass
GPIO.cleanup()

Hmmm…. that doesn't seem to work… sniff… let's try with some debug outputs… and also, I just read on this page that GPIO is only available as root. So I updated the script to:

import RPi.GPIO as GPIO
from time import sleep
relay_pin = 14
GPIO.setmode(GPIO.BCM)
GPIO.setup(relay_pin, GPIO.OUT)
GPIO.output(relay_pin, 1)
try:
    while True:
        print("Toggling pin to 0")
        GPIO.output(relay_pin, 0)
        sleep(5)
        print("Toggling pin to 1")
        GPIO.output(relay_pin, 1)
        sleep(5)
except KeyboardInterrupt:
  pass
GPIO.cleanup()

And now running as root:

sudo python main.py

Crap… :-(: So I can see the outputs, and when using a voltmeter I can see the voltage going from 0V to 3.3V and vice versa but the relay will not react at all :-(!

⇒ So I've been thinking about how to “workaround this problem” but unfortunately, I really cannot find anything that would make sense. Instead I think I should really just order a few SRD-03VDC-SL-C components from amazon and wait a couple of days befor continuing this little experiment!

[…3 days later…]

Hmmm! So…. I updated my test circuit to use a SRD-03VDC-SL-C component and… this is still not working ! :-| I mean, it's working fine when I use the GND pin with the 3V3 pin for instance. But as soon as I try to use a GPIO pin (+GND or +3V3) then it doesn't work anymore. How could that be ?!

… Oh… okay, I see now: just found this page: basically the problem is, we cannot draw any power from the GPIO pin itself (just about 16mA) (but we can draw much more from the 3V3 or 5V pins, that's why those pins will works!).

Conclusion then is: I need to place a transistor on the GPIO pin to control the load activation, as shown for instance on this page: https://raspberrypi.stackexchange.com/questions/41173/how-to-switch-on-off-a-circuit-using-gpio

Question then is of course: what kind of transistor should that be and do I have any of them available ? :-) Let's find out. I have:

⇒ And indeed, if we check the relay on PCB, there is a resistance R1, an transistor Q1, a LED, etc: this is definitely what we are after, so I tried using that and it just worked! In fact I can provide either 3V3 or 5V as input power and it works in both cases. All good!

relay_on_pcb.jpg

Building a web service

Now it's time to move online :-)!

I found this article which seems to be exactly what I want to do, so let's use that as a starting point.

OK we get our hello world message when navigating to the local page: http://192.168.1.2/

Now let's create a minimal HTML template templates/index.html with the following content:

<!DOCTYPE html>
   <head>
      <title>{{ title }}</title>
   </head>
   <body>
      <h1>Hello, World!</h1>
      <h2>The date and time on the server is: {{ time }}</h2>
   </body>
</html>

And we update our python script as follow:

from flask import Flask, render_template
import datetime
app = Flask(__name__)
@app.route("/")
def hello():
   now = datetime.datetime.now()
   timeString = now.strftime("%Y-%m-%d %H:%M")
   templateData = {
      'title' : 'HELLO!',
      'time': timeString
      }
   return render_template('index.html', **templateData)
if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)

OK! Working just fine.

And finally we will now add support to perform a GPIO action with a button click. Let's update out python script as follow:

import RPi.GPIO as GPIO
from flask import Flask, render_template, request, redirect, url_for 
from time import sleep
import datetime

app = Flask(__name__)

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

#define actuators GPIOs
gatePin = 14

#initialize GPIO status variables
gateState = 0

# Define led pins as output
GPIO.setup(gatePin, GPIO.OUT)   

# turn relay OFF: 
GPIO.output(gatePin, GPIO.LOW)

@app.route("/")
def root():
  return redirect(url_for('index'))

@app.route("/index")
def index():
   now = datetime.datetime.now()
   timeString = now.strftime("%Y-%m-%d %H:%M")
   templateData = {
      'title' : 'HELLO!',
      'time': timeString
      }
   return render_template('index.html', **templateData)

@app.route("/<deviceName>/<action>")
def action(deviceName, action):
  global gateState
  if deviceName == 'entrance' and action == "trigger":
    if gateState == 0:
      print("Activating entrance.")
      GPIO.output(gatePin, GPIO.HIGH)
      gateState = 1
      sleep(0.5)
      GPIO.output(gatePin, GPIO.LOW)
      gateState = 0
    else:
      print("Entrance signal already triggered.")
  
  return redirect(url_for('index'))

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)

And we add the required button on our index page:

<!DOCTYPE html>
   <head>
      <title>GPIO Control</title>
      <link rel="stylesheet" href='../static/style.css'/>
   </head>
   <body>
    <h2> Commands </h2>
    <h3> 
      Entrance gate control: 
      <a href="/entrance/trigger" class="button">Activate</a>  
    </h3>
   </body>
</html>

And we also define the button class as follow:

.button {
  font: bold 15px Arial;
  text-decoration: none;
  background-color: #EEEEEE;
  color: #333333;
  border-radius: 3px;
  padding: 2px 6px 2px 6px;
  border-top: 1px solid #CCCCCC;
  border-right: 1px solid #333333;
  border-bottom: 1px solid #333333;
  border-left: 1px solid #CCCCCC;
}

⇒ Cool LOL! It's working here too: I can hear my relay clicking behing me when I click the button ;-)!

Adding samba access on raspberry pi

Editing 1 or 2 files through an ssh connection a couple of times is one thing, but trying to inject a lot of changes this way with tests and errors is becoming quite painful. So now, the next task that seems the most important to me is to figure out how to provide a shared folder access to my pi drive with samba. So let's get started:

⇒ And with that I can now connect to the shared folder \\192.168.1.2\shared: good! It should now be much easier to edit our python scripts using Visual Studio Code directly :-)

Using a post request

The above minimal webserver designed with Flask is working very well already. Yet, I would like to try something a little different now: currently I'm simply sending a standard “GET” request to perform our action, yet, I think it should also be possible to perform a “POST” request instead. And in that case, I could provide additional fields in the post data map.

So let's see how we could update the code to achieve this:

See this page for reference.

⇒ yeeeppeee! It works perfectly!

Build a minimal ionic app

Continuing on our journey, now I want to create a minimal ionic app with a simple button to trigger the entrace gate activation action:

⇒ Unfortunately, this doesn't just work out of the box since we have a CORS issue:

Access to XMLHttpRequest at 'http://192.168.1.2/trigger' from origin 'http://localhost:8182' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

⇒ I think should install flask-cors to handle that.

⇒ Oh, okay, it seems that would be because flask is not parsing the data I send correctly and according to this page I should try using request.json directly. Let's have a try… OK!

Great! Both the curl command and ionic app are now working as expected ;-)!

Preparing to build android app

I must provide the required arguments directly on the command line for cap init because cygwin is detected as a “non-interactive shell”

homectrl_in_android_virtual_device.jpg

And guess what? Clicking on the button is still working just fine [I must be lucky today!] :-)!

Signing release apk

To install on android < 7.0 we really need to keep the signature v1 version enabled, otherwise the application will not install at all.

Adding support for redirection from nginx server

So our entrance gate control mechanism is working great, but for the moment, the API REST point is only reachable on our local network (ie. from http://192.168.1.2/trigger): not terribly useful… or, at least, this could be improved further if I could allow external access from my nginx server. Let's see how I can do that.

⇒ I just added the following location redirection in my api.nervtech.org site config:

    location /homectrl/ {
      proxy_set_header Host $host/homectrl;
      proxy_pass http://192.168.1.2:80/;
      proxy_redirect off;
    }

Then we test with a curl command:

curl -H "Content-Type: application/json" -d '{"device": "entrance", "action":"trigger"}' -X POST https://api.nervtech.org/homectrl/trigger

And victory! [It feels almost too easy…]

I should now update my ionic app accordingly. Done

Updating icon for android app

⇒ See this page as reference.

Auto starting homectrl server

Currently I'm manually starting the homectrl server with the command sudo python3 server.py, but instead I should really be starting that process automatically, and then monitor it to ensure it is always running.

So I will use the following script to do so (note: I renamed the “server.py” script to “homectrl.py” to make it less confusing):

#!/bin/bash

nump=$(ps -ef | grep '[/]home/pi/shared/apps/gatectrl/homectrl.py' | wc -l)
# echo "Num processes: ${nump}"

if [ $nump -eq 0 ]; then
  echo "Starting homectrl process."
  sudo python3 /home/pi/shared/apps/gatectrl/homectrl.py 
  echo "homectrl process done."
else
  echo "homectrl process already running."
fi

And then I should simply edit my crontab to execute that script regularly:

crontab -e
* * * * * bash /home/pi/shared/apps/gatectrl/run.sh 2>&1 1>>/home/pi/shared/apps/gatectrl/homectrl.log

OK! All good.

Displaying confirmation when activation is done

Last but not least, it would be very good to display a message inside our android application stating that the activation was done correctly or not, because otherwise, we are never quite sure if the network is very slow… Let's handle that.

⇒ I thus updated the code to display a toast message depending on the success of the request:

  async presentToast(msg:string, color:string) {
    this.toast = await this.tctrl.create({
      message: msg,
      duration: 3000,
      color: color
    });

    this.toast.present();
  }

And then when actually sending a request we do something with the result we get:

    this.http.post<any>(addr, {device: 'entrance', action: 'trigger'}).subscribe(data => {
      console.log("Received reply: "+JSON.stringify(data))
      
      this.requestSent = false;

      if(data['status'] == 'OK') {
        this.presentToast("Gate activated successfully.", "success");
      }
      else {
        this.presentToast(data['message'], "warning");
      }

    })

Conclusion

And with those latest changes when I click the “Activate” button on my android app, I eventually receive a toast indicating that the activation was done successfully! This is very handy to know exactly when your action was indeed taken into account and to avoid clicking too many times on the button because you are not sure anything is happening lol.

⇒ Anyway, I think I should stop here for this time since the application is working fine, and we will see in the coming days if there is anything to change!

Meanwhile, happy hacking everyone!