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.

Bex
  • 2,929
  • 3
  • 26
  • 34
Xavier
  • 41
  • 1
  • 2

2 Answers2

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.

Brick
  • 1,375
  • 2
  • 14
  • 20
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.

calcinai
  • 179
  • 1
  • 13