0

I am designing a Raspberry Pi based home automation unit in which the Pi will communicate with several atmega328p microcontrollers (in each room) via nrf24l01. Atmega side will not be a problem, but I am not an expert in server/Raspberry/Linux.

I am using apache as the webserver. By browsing a few days, I have managed to design a HTML webpage in PHP which is calling a Python script. Right now I am experimenting with GPIO toggling.There are two Python scripts which are used to ON/OFF a LED.

The main problem is, after calling the Python script, the PHP script is not returning to the main webpage and everything is being white. I am attaching my code below. Please take a look. Any help is appreciated. But just remember, I am not an expert in Linux/webpage development, so please be a little descriptive.

index.php

<DOCTYPE html>    
<html>    
<head>
<title>Room automation</title>
<?php
exec("python LED_OFF.py");
?>
<style>
  body
        {
            font-family: comic sans ms;
            text-align:center;
            background:#CACFD2;
        }
        h1
        {
            text-shadow: 10px 10px 10px #aaaaaa ;
        }


</style>


</head>

<body>
<h1>Sharanya's room automation</h1>
</body>
<img src="red_btn.png" id="btn_l" onmouseover="this.src='blue_btn.png'" onmouseout="this.src='red_btn.png'"  onclick="parent.location='do.php' " style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_2" style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_3" style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_4" style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_5" style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_6" style="width:70px;height:70px;">
</html>

Now, the do.php

<?php
echo exec("python LED_ON.py");
echo("Hello");
?>

And the LED_ON.py

import sys
import RPi.GPIO as GPIO
import time


GPIO.setmode(GPIO.BCM)
GPIO.setup(14,GPIO.OUT)
GPIO.output(14,GPIO.HIGH)

Main page

After clicking the leftmost button

  • It seems like this post is missing some / all of the php. Did you have a copy/paste error or a formatting problem? – Brick Aug 24 '17 at 17:56
  • Also, please post the python script. (My guess is that the error is there....) – Brick Aug 24 '17 at 17:58
  • Please check now!! – S.Das Aug 24 '17 at 18:04
  • That's better. But now this seems to work.... What's the problem? Do you think it should / want that it go to your room automation page instead of showing "Hello" on a white screen? I'm unclear from your description. – Brick Aug 24 '17 at 18:06
  • yes,I want the script to return to the main page.That is not happening. – S.Das Aug 24 '17 at 18:07
1

This seems to behave properly. I think your expectation of what happens on the click is probably wrong.

What seems to happen (correctly) is that you click the button, and the browser attempts to load do.php. That file attempts to execute your Python and print the text it gives on standard output. Your Python script writes nothing to standard output, so that part is blank. Then it echoes the text "Hello", which you can see does appear in your browser.

If you want the main page to reload, then at some point in your flow, you're going to have to tell it that you want that to happen. Exactly how to implement that is a design decision.

Clues for moving forward: I don't think PHP is the best tool for this. Usually PHP is for making the webpage content dynamic, not for executing code on the server. Probably better would be javascript and / or a server-side cgi-script. Of those, I'm more familiar with cgi. You'd have to configure the server for that (a whole different set of questions) and then have the cgi script (which could call your Python) write out the HTML for your "main" page to standard out when it's done.

  • OK...I tried that previously.But due to non consistency,I forgot all!!I will try tomorrow using CGI scripts and let you know.....Although i found a solution,adding this line <header("Location: index.php");> is making the do script to reload the main webpage. – S.Das Aug 24 '17 at 18:36
0

Addressing your main problem, a simple header redirect at the end of go.php will make the page redirect back to index.php after the python script has been executed. e.g.

header('Location: index.php');

The thing to be careful with, is that this will only work if your script doesn't output anything to page prior, so you'll need to remove the echo("Hello");

In general, you're on the right track, but you can make your life a lot easier. Here are a few other recommendations based on what I can see:

Tidy up your HTML

Firstly, make sure all your tags are matched and closed, e.g. if you open a <div> tag, you need to close it with a </div> tag. You should also pay attention to the nesting - I can see that in your example, your <img> tags are outside the body. For what you're doing, this may not cause any issues, but it is still good practise.

Leverage CSS

One of the greatest things about programming, is the ability to write something only once. In your example, you're going to end up with a lot of copy+paste to make the button hover effect. Eventually, you'll end up with something like

<img src="red_btn.png" id="btn_1" onmouseover="this.src='blue_btn.png'" onmouseout="this.src='red_btn.png'"  onclick="parent.location='do.php' " style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_2" onmouseover="this.src='blue_btn.png'" onmouseout="this.src='red_btn.png'"  onclick="parent.location='do.php' " style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_3" onmouseover="this.src='blue_btn.png'" onmouseout="this.src='red_btn.png'"  onclick="parent.location='do.php' " style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_4" onmouseover="this.src='blue_btn.png'" onmouseout="this.src='red_btn.png'"  onclick="parent.location='do.php' " style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_5" onmouseover="this.src='blue_btn.png'" onmouseout="this.src='red_btn.png'"  onclick="parent.location='do.php' " style="width:70px;height:70px;">
<img src="red_btn.png" id="btn_6" onmouseover="this.src='blue_btn.png'" onmouseout="this.src='red_btn.png'"  onclick="parent.location='do.php' " style="width:70px;height:70px;">

See how much duplication is there? If you use CSS, you can achieve it in a far simpler way:

<div id="controls">
    <a href="go.php?pin=14"></a>
    <a href="go.php?pin=15"></a>
    <a href="go.php?pin=16"></a>
    <a href="go.php?pin=17"></a>
    <a href="go.php?pin=18"></a>
    <a href="go.php?pin=19"></a>
</div>

and the CSS

#controls a {
    display: inline-block;
    width: 70px;
    height: 70px;
    background-image: url("green_btn.png");
    background-size: contain;
}

#controls a:hover {
    background-image: url("red_btn.png");
}

Get a little clever with Javascript

You can avoid your main issue entirely by making the buttons request go.php via javascript/ajax. This will mean that you don't actually reload the page when you click back button and will be a much nicer experience.

Consider adding in something like

<script type="text/javascript">
    document.getElementById('controls').addEventListener('click', function(e){
        e.preventDefault();

        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", e.target.href, true);
        xmlhttp.send();

    }, false);

</script>

This does largely what your inline tags (onclick="parent.location='do.php'") were doing, but in an async way. The e.preventDefault() line stops the buttons preforming their default action, then the XMLHttpRequest makes the ajax request. You'll notice that you only need this once and it'll apply the functionality to each button.

In terms of go.php, there are also some improvements that can be made.

Get rid of the Python script!

Have a look at PHPi - this allows native PHP control of the GPIO - exactly what it looks like you're trying to achieve. Using this library, you can control the pins directly from within this script. e.g.

require 'vendor/autoload.php';

use Calcinai\PHPi\External\Output;

$board = \Calcinai\PHPi\Factory::create();

$pin = $board->getPin($_GET['pin']); //BCM pin number

$output = new Output($pin); 
$output->toggle();

echo $pin->getLevel();

The above script will take the pin number supplied from the button and toggle it. It will echo a 1 or a 0 in the response to indicate the new level. With a little change to the above javascript, we can make the buttons on the page reflect the new state. You will need to download the build from GitHub or install via composer in order to use this library.

xmlhttp.onreadystatechange = function() {
    if (xhr.readyState == XMLHttpRequest.DONE) {
        if(xhr.responseText == '1'){
            e.target.className = 'on';
        } else {
            e.target.className = 'off';
        }
    }
}

Putting it all together:

index.php:

<!DOCTYPE html>
<html>
<head>
    <title>Room automation</title>

    <style>
        body {
            font-family: "Comic Sans MS", sans-serif;
            text-align: center;
            background: #cacfd2;
        }

        h1 {
            text-shadow: 10px 10px 10px #aaaaaa;
        }

        #controls a, #controls a.on:hover {
            display: inline-block;
            width: 70px;
            height: 70px;
            background-image: url("red_btn.png");
            background-size: contain;
        }

        #controls a:hover, #controls a.on {
            background-image: url("green_btn.png");
        }
    </style>

</head>
<body>

    <h1>Sharanya's room automation</h1>

    <div id="controls">
        <a href="go.php?bcm_pin=1"></a>
        <a href="go.php?bcm_pin=2"></a>
        <a href="go.php?bcm_pin=3"></a>
        <a href="go.php?bcm_pin=4"></a>
        <a href="go.php?bcm_pin=5"></a>
        <a href="go.php?bcm_pin=6"></a>
    </div>

</body>

<script type="text/javascript">
    document.getElementById('controls').addEventListener('click', function(e){
        e.preventDefault();

        var xmlhttp = new XMLHttpRequest();
        xmlhttp.onreadystatechange = function() {
            if (xhr.readyState == XMLHttpRequest.DONE) {
                if(xhr.responseText == '1'){
                    e.target.className = 'on';
                } else {
                    e.target.className = 'off';
                }
            }
        }

        xmlhttp.open("GET", e.target.href, true);
        xmlhttp.send();
    }, false);

</script>
</html>

go.php:

<?php

require 'vendor/autoload.php';

use Calcinai\PHPi\External\Output;

$board = \Calcinai\PHPi\Factory::create();

$pin = $board->getPin($_GET['pin']); //BCM pin number

$output = new Output($pin);
$output->toggle();

echo $pin->getLevel();

Obviously there's a lot of info here, but I'm hoping it helps you or others with similar issues, or just gives you some ideas to think about!

Disclosure: The PHPi library is something that I've written and maintain

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.