4

I have spent two days on this and have tried nearly everything I could find. I am using an apache server (2.4.10).

I have two files in a folder called testPythonPHP that is located in the root folder of my server (/var/www/html). The files are callPythonFromPHP.php and pythonReturn.py. I call the python script from the PHP script using the exec command. Everything works fine before I try to use the RPi.GPIO module in the python script. Before using the RPi.GPIO module, I get the desired output.

Here is the PHP code:

<?php

exec(" python /var/www/html/testPythonPHP/pythonReturn.py" , $status, 
$return );

echo( $status[0] ." is status and ".$return." is return and user is ");

echo exec( "whoami");

?>

Here is my python code:

import RPi.GPIO as GPIO
import time

butPin = 25
ledPin = 24

GPIO.setmode (GPIO.BCM)
#GPIO.setup (ledPin, GPIO.OUT)
#GPIO.setup (butPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
#GPIO.output (ledPin, GPIO.LOW)

def bullspit():
    cat = "3"
    dog = "4"
    catDog = cat + dog
    GPIO.cleanup()
    return catDog


if __name__ == '__main__':
    print bullspit()

Here is the output to the browser:

34 is status and 0 is return and user is www-data

Once I un-comment any of the code in the python script, my output becomes:

is status and 1 is return and user is www-data

I no longer get the returned value from the python script and I now get the 1 return status (indicating something went wrong). I have tried changing permissions and using different commands (not that I can guarantee those were done correctly).

I feel like I am on the right track but cannot get this to work. Does anyone know what my mistake is or if there is another GPIO module I can use that will work with python and read analog values?

My goal is to use python to read in an analog value from a MCP3008 chip and return the value to the PHP script where I will dictate different GPIO pins to write high or low depending on the returned value. I tested a variation of the python file in the terminal and was able to print different return values based on an input button being high or low.

I would settle for reading in analog values from the PHP script, but it still seems like a permission issue and I will likely run into the same problem.

8
  • Did you try to run your python script on the command line? What happens? Why are you using php at all? Why not write all of it in python?
    – Bex
    Sep 6, 2017 at 7:26
  • Have you investigated the error message from running the python code directly? (python pythonReturn.py) Sep 6, 2017 at 15:53
  • Have a look at this: github.com/calcinai/phpi/blob/master/examples/mcp300x.php - if you feel it's relevant to your question, I can write a full answer below.
    – calcinai
    Sep 6, 2017 at 22:37
  • When I run the python script in the command line, I get the expected output of 34. I am using php because I am modifying this instructable form TheFreeElectron: [instructables.com/id/…. It uses php and javascript to update picture on the browser. However, instead of changing the picture, and toggling the state of the GPIO pin, each time the picture is clicked, I want to change the picture, and GPIO state, based on the analog value I read in. I also tried running python code directly (without path) and it ran just the same.
    – Xavier
    Sep 6, 2017 at 23:33
  • @calcinai, your code for reading in the analog value in php is helpful except I do not want to use the PWM, although I will put that in my back pocket for later. I simply want to read in the analog value and set other pins high or low based on a value threshold. I planned on tackling this route next with the help of this: [packagist.org/packages/tgeindre/php-gpio]. However, I really want to get the call from php to python to work properly as this could prove useful on other projects down the road too. Which one is the "better" approach is something I am unsure of.
    – Xavier
    Sep 6, 2017 at 23:40

2 Answers 2

1

Apache creates its own users to run its jobs. When run as a php command, you are almost surely running as some such Apache-created user that has different permissions than your user account. Accessing the GPIO requires special permission, which the php user probably doesn't have. That will cause it to fail when called, which is exactly what you are seeing.

To further debug this, you should check the error logs created when the job fails and possibly identify the user that is executing that job. These links will help:

Summarizing the key point about the error logging, the error usually appears under /var/log/apache2 on the Pi. (You'll see other potential locations listed for other hardware and software options at the stack overflow questions since they are more general.)

To address the underlying permissions error, if that's what it ultimately is, you may have a couple of options. You might be able to grant the appropriate permissions to the php user, or your might run it with sudo from your php script. That, in turn, may require you to add the php use to the list of sudoers. Be careful with either option - especially if there's public access - because you'll be allowing external control of the pins on your Pi!

Having mentioned how to do this, I think it's worth noting that this probably indicative of a bad design anyway. Based on what you said, it seems like php is the wrong tool for this job. If you must allow changes in state to your Pi via web, you're probably better using cgi-bin programs instead. Usually php is for serving dynamic content in the webpage, not for changing the state of the server. (In this case, the Pi is the server.) That's a whole different set of questions and issues though.

1

It's almost certainly a permissions issue. Ordinarily, you'd just add www-data to the gpio group (usermod -aG gpio www-data), but due to the fact you're accessing the SPI, it's a bit more complex than usual. You have two choices

  1. Run apache as root (not recommended)
  2. Run your script as a background process

Option 1 would quickly tell you if it's a permissions issue, and can be done by changing the user (you'll probably find it in /etc/apache2/envvars).

Option 2 is really a better approach, but is more work. What you need to think about is a long-lived process running in the background, and a way to interact with this from the web thread. This can be done by http/queue/file/fifo/socket among others. I'd recommend having a look at some of the react libraries, or ZeroMQ

With all that in mind, using the PHPi library, you can do this completely in PHP. Here's an example based off one of the examples in the library for interacting with that ADC.

include 'vendor/autoload.php';

use Calcinai\PHPi\Peripheral\SPI;
use Calcinai\PHPi\Pin\PinFunction;
use Calcinai\PHPi\External\ADC\Microchip\MCP3008;

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

//Flip the appropriate pins to their alt functions
$board->getPin(10)->setFunction(PinFunction::SPI0_MOSI);
$board->getPin(9)->setFunction(PinFunction::SPI0_MISO);
$board->getPin(11)->setFunction(PinFunction::SPI0_SCLK);
$board->getPin(8)->setFunction(PinFunction::SPI0_CE0_N);

$adc = new MCP3008($board->getSPI(SPI::SPI0), 0);
$pin = $board->getPin(18);

//In 10-bit, will be between 0 and 1024
$value = $adc->getChannel(0)->read();
if($value > 500){
    $pin->high();
} else {
    $pin->low();
}

Usually you'd be running this as a process, rather than directly via apache.

6
  • I really want to use the PHPi library now that I have looked into it. I tried testing my install by running the led.php example. I got this when running from the terminal: PHP Warning: include(/home/pi/../vendor/autoload.php): failed to open stream: No such file or directory in /home/pi/led.php on line 13 PHP Warning: include(): Failed opening '/home/pi/../vendor/autoload.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /home/pi/led.php on line 13 PHP Fatal error: Class 'Calcinai\PHPi\Factory' not found in /home/pi/led.php on line 15.
    – Xavier
    Sep 7, 2017 at 3:34
  • How did you install the library? Did you download the zip or use composer?
    – calcinai
    Sep 7, 2017 at 3:35
  • I used composer. I had to use sudo php composer.phar calcinai/phpi for it to install phpi. I will retry after work tonight.
    – Xavier
    Sep 7, 2017 at 12:54
  • That's really odd. It's likely you'd need sudo to run it, but it should install as your user.
    – calcinai
    Sep 7, 2017 at 20:12
  • I am reloading the Raspian image to my SD card so I can start fresh. I believe I tampered with too many permissions (recursively) and I don't know where I went wrong but I am unable to write to a lot of files. When I restart, I want to run a PHP script to monitor the analog input and write a pin high or low (using phpi). Can I then use my web server to view the state of the pin to update an image based on the state? I.e. have my process script control the state of the pin and another script view the state of the pin. Process would use phpi and other script would use GPIO module.
    – Xavier
    Sep 9, 2017 at 17:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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