piphp / gpio Goto Github PK
View Code? Open in Web Editor NEWA PHP library for accessing the GPIO pins on a Raspberry Pi.
License: MIT License
A PHP library for accessing the GPIO pins on a Raspberry Pi.
License: MIT License
Should the flyweight pattern be used (so that there is only ever one instance of any pin as they are remembered by the factory)?
Again - interested to hear thoughts?
OK, I really believe I have tried everything. I am constantly getting the permission fatal error:
PHP Fatal error: Uncaught RuntimeException: fopen(/sys/class/gpio/export): failed to open stream: Permission denied in /var/www/html/vendor/piphp/gpio/src/FileSystem/FileSystem.php:55
I've tried every solution I was able to find online. I've tried adding www-data user to gpio group, which strangely resulted in Apache not starting at all (not sure why). I even tried dumb last resorts as setting permissions to 777 of whole /sys/class/gpio folder recursively, or adding unlimited access to www-data user in /etc/sudoers.
Still the same error. Any help?
This morning @AndrewCarterUK put out a call for a new maintainer: https://twitter.com/AndrewCarterUK/status/1291697455663325184
@Sam-Burns and I offered to step in and take over the project and I'm excited to say hello and share some initial plans with everyone.
A general outline of my plans for the GPIO project:
I'd love to know what OS our users are using on their Pis, here is a short straw poll: http://www.strawpoll.me/20734890
Raspberry Pi OS has PHP 7.0 -> 7.3 it seems. I think we start with 7.3 as a base target of compatibility and drop everything from there unless there is a very pressing need? If you have such a use case please comment!
If you have any questions for us please ask them here!
No php version is declared, indeed the whole "require" section is missing from composer.json (didn't look at code, so maybe some other ext could be missing too)
Hi,
Does it works on PHP7 ?
Hi There.
I am sorry to bring this up, but could the permissions settings also be addressed here, because this does not work without them.
When user starts this from the pure clean jessie image and installs apache2 with php5, GPIO permissions are not right
Thank you for your considerations.
I didn't found any PWM support in this library, how do you achieve this ?
Nice to see this project has new life!
I however came across a bug which might be my fault. I am subscribing to a MQTT server and it stays connected listening for new messages to come in.
Inside that loop, I had the following code:
foreach ($subscribe->loop($client) as $message) {
// bla bla bla, some irrelevant code
if ($stateFile['command'] !== $command) {
$gpio = new GPIO();
$pin = $gpio->getOutputPin(RELAY_PIN);
if ($command === 'on') {
$pin->setValue(PinInterface::VALUE_LOW);
} else {
$pin->setValue(PinInterface::VALUE_HIGH);
}
}
}
This meant that the first time this code was called, everything went ok. The second time however, it errored out:
PHP Fatal error: Uncaught RuntimeException: fwrite(): write of 2 bytes failed with errno=16 Device or resource busy in /home/ubuntu/gpio/controlVentilatorBaseroom/vendor/piphp/gpio/src/FileSystem/FileSystem.php:54
Stack trace:
#0 /home/ubuntu/gpio/controlVentilatorBaseroom/vendor/piphp/gpio/src/FileSystem/FileSystem.php(45): PiPHP\GPIO\FileSystem\FileSystem->exceptionIfFalse()
#1 /home/ubuntu/gpio/controlVentilatorBaseroom/vendor/piphp/gpio/src/Pin/Pin.php(115): PiPHP\GPIO\FileSystem\FileSystem->putContents()
#2 /home/ubuntu/gpio/controlVentilatorBaseroom/vendor/piphp/gpio/src/Pin/Pin.php(55): PiPHP\GPIO\Pin\Pin->writePinNumberToFile()
#3 /home/ubuntu/gpio/controlVentilatorBaseroom/vendor/piphp/gpio/src/Pin/Pin.php(39): PiPHP\GPIO\Pin\Pin->export()
#4 /home/ubuntu/gpio/controlVentilatorBaseroom/vendor/piphp/gpio/src/Pin/OutputPin.php(17): PiPHP\GPIO\Pin\Pin->__construct()
#5 /home/ubuntu/gpio/controlVentilatorBaseroom/vendor/piphp/gpio/src/GPIO.php(41): PiPHP\GPIO\Pin\OutputPin->__construct()
#6 /home/ubuntu/gpio/controlVenti in /home/ubuntu/gpio/controlVentilatorBaseroom/vendor/piphp/gpio/src/FileSystem/FileSystem.php on line 54
I fixed it by moving the following piece of code out of the loop:
$gpio = new GPIO();
$pin = $gpio->getOutputPin(RELAY_PIN);
I've been running this code for a few years now and this wasn't an issue before. I understand the problem and I know it is not desirable to create a new instance of the same pin within the same flow of a program, so here my question: was this a bug on my side or do I make an attempt at trying to fix this one?
Greetings.
Edge detection is primarily used for interrupt detection - sometimes we only care about interrupts LOW -> HIGH for example. However, it looks like this is being set via the Pin
class (and can be done for output pins, which isn't useful). Would it make more sense to set this on the interrupt watcher instead?
Creating a new 'output pin' instance rewrites to the sysfs GPIO direction file and resets the pin state.
Solution is to check to see if the pin is already an output pin and only write to the direction file if it isn't.
Tag: @alfredomova
Does this support extending GPIO's via a MCP23017 chip?
Many other GPIO libraries require you to set the direction at the same time the pin is declared for use - either via the constructor or some other initialization function. This makes sense, because you're probably never going to change the direction of a pin during execution without rewiring your project.
Would it make sense to do the same thing with the Pin
class? Basically change its constructor to include a $direction
parameter? Or alternatively create separate InputPin
and OutputPin
classes, where the setValue()
method is only available on the latter?
I'd be happy to submit a PR for either change if you're interested.
I cannot seem to get the interrupt functionality working - my callback is always fired immediately, regardless of the timeout I set or the state of the pin.
I'm using the exact code from the README, but with two changes:
4
in the code)The screen floods with these messages:
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
If I change the state of the pin, I'll see the value change accordingly:
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 1
But the callback still fires rapidly when the state isn't changing.
I tried testing the underlying stream_select()
myself by running the following commands as root...
echo 4 > /sys/class/gpio/unexport # Start from a clean state
echo 4 > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio4/direction
echo "both" > /sys/class/gpio/gpio4/edge
Followed by this PHP script as root:
<?php
$r = $w = [];
$e = [fopen('/sys/class/gpio/gpio4/value', 'r')];
$val = stream_select($r, $w, $e, 99999);
var_dump($val);
The script immediately ends with the following output:
int(1)
This occurs both when nothing is connected to the pin (value is HIGH) and when the pin is connected directly to GND (value is LOW).
I wonder if perhaps this only occurs with certain Pi devices? I'm using a Raspberry Pi 3 running Raspbian Jessie.
Hello,
i try add static analyse tool phpstan to project and here is output and choise what to do.
Here is commit where are changes https://github.com/h4kuna/GPIO/commit/93fa0c099d61d0a9fb9b2e3eb97032034ecfef8e run it by ./test/phpstan
.
I will create new class with this php funcions what return two value and make it strictly like this. But here is need only fopen
, fwrite
and stream_get_contents
.
And create own excenption instead of global RuntimeException.
------ ---------------------------------------------------------------------------------------------------------------------------------
Line src/FileSystem/FileSystem.php
------ ---------------------------------------------------------------------------------------------------------------------------------
29 Method PiPHP\GPIO\FileSystem\FileSystem::getContents() should return string but returns resource.
29 Parameter #1 $result of method PiPHP\GPIO\FileSystem\FileSystem::exceptionIfFalse() expects resource|false, string|false given.
42 Method PiPHP\GPIO\FileSystem\FileSystem::putContents() should return int but returns resource.
42 Parameter #1 $result of method PiPHP\GPIO\FileSystem\FileSystem::exceptionIfFalse() expects resource|false, int|false given.
53 Offset 'message' does not exist on array('type' => int, 'message' => string, 'file' => string, 'line' => int)|null.
------ ---------------------------------------------------------------------------------------------------------------------------------
Here are two way, make it strtly by php typehint or for this moment only by annotation. I'm vote for first choice and support with php 7.3+, it will be BC break. Here is opended PR #38
------ ---------------------------------------------------------------------------------------------------
Line src/GPIO.php
------ ---------------------------------------------------------------------------------------------------
14 Property PiPHP\GPIO\GPIO::$fileSystem has no typehint specified.
15 Property PiPHP\GPIO\GPIO::$streamSelect has no typehint specified.
40 Method PiPHP\GPIO\GPIO::getOutputPin() has parameter $exportDirection with no typehint specified.
------ ---------------------------------------------------------------------------------------------------
------ ----------------------------------------------------------------------------------------------
Line src/Interrupt/InterruptWatcher.php
------ ----------------------------------------------------------------------------------------------
10 Property PiPHP\GPIO\Interrupt\InterruptWatcher::$fileSystem has no typehint specified.
11 Property PiPHP\GPIO\Interrupt\InterruptWatcher::$streamSelect has no typehint specified.
12 Property PiPHP\GPIO\Interrupt\InterruptWatcher::$streams has no typehint specified.
13 Property PiPHP\GPIO\Interrupt\InterruptWatcher::$pins has no typehint specified.
14 Property PiPHP\GPIO\Interrupt\InterruptWatcher::$callbacks has no typehint specified.
43 Method PiPHP\GPIO\Interrupt\InterruptWatcher::register() has no return typehint specified.
62 Method PiPHP\GPIO\Interrupt\InterruptWatcher::unregister() has no return typehint specified.
78 Method PiPHP\GPIO\Interrupt\InterruptWatcher::watch() has no return typehint specified.
------ ----------------------------------------------------------------------------------------------
------ -------------------------------------------------------------------------------------------------------
Line src/Interrupt/InterruptWatcherInterface.php
------ -------------------------------------------------------------------------------------------------------
15 Method PiPHP\GPIO\Interrupt\InterruptWatcherInterface::register() has no return typehint specified.
22 Method PiPHP\GPIO\Interrupt\InterruptWatcherInterface::unregister() has no return typehint specified.
29 Method PiPHP\GPIO\Interrupt\InterruptWatcherInterface::watch() has no return typehint specified.
------ -------------------------------------------------------------------------------------------------------
------ -----------------------------------------------------------------------------
Line src/Pin/InputPin.php
------ -----------------------------------------------------------------------------
36 Method PiPHP\GPIO\Pin\InputPin::setEdge() has no return typehint specified.
------ -----------------------------------------------------------------------------
------ --------------------------------------------------------------------------------------
Line src/Pin/InputPinInterface.php
------ --------------------------------------------------------------------------------------
24 Method PiPHP\GPIO\Pin\InputPinInterface::setEdge() has no return typehint specified.
------ --------------------------------------------------------------------------------------
------ -----------------------------------------------------------------------------------------------------------
Line src/Pin/OutputPin.php
------ -----------------------------------------------------------------------------------------------------------
15 Method PiPHP\GPIO\Pin\OutputPin::__construct() has parameter $exportDirection with no typehint specified.
31 Method PiPHP\GPIO\Pin\OutputPin::setValue() has no return typehint specified.
------ -----------------------------------------------------------------------------------------------------------
------ ----------------------------------------------------------------------------------------
Line src/Pin/OutputPinInterface.php
------ ----------------------------------------------------------------------------------------
12 Method PiPHP\GPIO\Pin\OutputPinInterface::setValue() has no return typehint specified.
------ ----------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------
Line src/Pin/Pin.php
------ ------------------------------------------------------------------------------------------------
27 Property PiPHP\GPIO\Pin\Pin::$fileSystem has no typehint specified.
28 Property PiPHP\GPIO\Pin\Pin::$number has no typehint specified.
30 Property PiPHP\GPIO\Pin\Pin::$exported has no typehint specified.
57 Method PiPHP\GPIO\Pin\Pin::export() has no return typehint specified.
72 Method PiPHP\GPIO\Pin\Pin::unexport() has no return typehint specified.
82 Method PiPHP\GPIO\Pin\Pin::isExported() has no return typehint specified.
92 Method PiPHP\GPIO\Pin\Pin::getDirection() has no return typehint specified.
106 Method PiPHP\GPIO\Pin\Pin::setDirection() has no return typehint specified.
106 Method PiPHP\GPIO\Pin\Pin::setDirection() has parameter $direction with no typehint specified.
163 Method PiPHP\GPIO\Pin\Pin::writePinNumberToFile() has no return typehint specified.
------ ------------------------------------------------------------------------------------------------
------ ----------------------------------------------------------------------------------
Line src/Pin/PinInterface.php
------ ----------------------------------------------------------------------------------
20 Method PiPHP\GPIO\Pin\PinInterface::export() has no return typehint specified.
25 Method PiPHP\GPIO\Pin\PinInterface::unexport() has no return typehint specified.
------ ----------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------
Line test/FileSystem/FileSystemTest.php
------ ------------------------------------------------------------------------------------------------------
11 Method PiPHP\Test\GPIO\FileSystem\FileSystemTest::testFileSystem() has no return typehint specified.
34 Method PiPHP\Test\GPIO\FileSystem\FileSystemTest::testBadFile() has no return typehint specified.
------ ------------------------------------------------------------------------------------------------------
------ ----------------------------------------------------------------------------------------------------------------
Line test/Pin/OutputPinTest.php
------ ----------------------------------------------------------------------------------------------------------------
12 Method PiPHP\Test\GPIO\Pin\OutputPinTest::testOutputPin() has no return typehint specified.
28 Method PiPHP\Test\GPIO\Pin\OutputPinTest::testOutputPinIsNotDoubleExported() has no return typehint specified.
------ ----------------------------------------------------------------------------------------------------------------
------ -------------------------------------------------------------------------------------------
Line test/Pin/InputPinTest.php
------ -------------------------------------------------------------------------------------------
11 Method PiPHP\Test\GPIO\Pin\InputPinTest::testInputPin() has no return typehint specified.
------ -------------------------------------------------------------------------------------------
Tests have specific errors. I will fix it at last.
------ ---------------------------------------------------------------------------------------------------------
Line test/FileSystem/VFS.php
------ ---------------------------------------------------------------------------------------------------------
9 Property PiPHP\Test\GPIO\FileSystem\VFS::$vfs has no typehint specified.
11 Method PiPHP\Test\GPIO\FileSystem\VFS::open() should return resource but return statement is missing.
22 Method PiPHP\Test\GPIO\FileSystem\VFS::putContents() should return int but return statement is missing.
30 Parameter #2 $subject of function preg_match expects string, int|string given.
------ ---------------------------------------------------------------------------------------------------------
------ ----------------------------------------------------------------------------------------------
Line test/Interrupt/InterruptWatcherTest.php
------ ----------------------------------------------------------------------------------------------
11 Method PiPHP\Test\GPIO\InterruptWatcherTest::testWatcher() has no return typehint specified.
17 Cannot access offset 1 on array<resource>|false.
18 Cannot access offset 1 on array<resource>|false.
27 Cannot access offset 0 on array<resource>|false.
28 Cannot access offset 0 on array<resource>|false.
69 Cannot access offset 1 on array<resource>|false.
72 Cannot access offset 1 on array<resource>|false.
73 Cannot access offset 1 on array<resource>|false.
79 Cannot access offset 1 on array<resource>|false.
86 Cannot access offset 1 on array<resource>|false.
87 Cannot access offset 1 on array<resource>|false.
------ ----------------------------------------------------------------------------------------------
First of all, I see no activity in this repo since a while ago, and even if I'm currently using it in a project of mine, are there any reasons that I shouldn't?
Now to the question.
First version of my code was using:
$pin[$sensore]->setEdge(InputPinInterface::EDGE_BOTH);
but then I realized I only was actually inerested to check when the input became from LOW to HIGH, so I changed it to
$pin[$sensore]->setEdge(InputPinInterface::EDGE_RISING);
What I noticed, tho, is that I kept getting the same amount of events of the first version.
It's a motion sensor which is activated, and then deactivates itself after 2-3 seconds, and even if I try and select only EDGE_RISING (activation in this case) I get an event both when sensor activates (LOW->HIGH) and when it deactivates (HIGH->LOW).
Shouldn't matter much as I can prune those event I'm not interested in, I just wonder if it wouldn't use less resources if it worked as intended.
Upon registering the pin with the interrupt watcher there is data available to read in the stream. This causes the watch()
method to trigger the callback on the first run of every newly registered pin.
Solution: read pin value file after registering the pin and then add it to the event loop.
I installed via composer:
$ php composer.phar require piphp/gpio
Using version ^0.4.0 for piphp/gpio
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
- Installing piphp/gpio (0.4.0): Downloading (100%)
Writing lock file
Generating autoload files
And then using this code in /var/www/html/index.php
use PiPHP\GPIO\GPIO;
use PiPHP\GPIO\Pin\PinInterface;
// Create a GPIO object
$gpio = new GPIO();
// Retrieve pin 18 and configure it as an output pin
$pin = $gpio->getOutputPin(4);
// Set the value of the pin high (turn it on)
$pin->setValue(PinInterface::VALUE_HIGH);
Results in
Fatal error: Uncaught Error: Class 'PiPHP\GPIO\GPIO' not found in /var/www/html/index.php:13 Stack trace: #0 {main} thrown in /var/www/html/index.php on line 13
Do you think there's a need for the InterruptWatcher
to have debouncing logic built-in? For example, when I run the code in the README example and toggle the connection between the GPIO pin and ground, I get the following result:
Pin 4 changed to: 1
Pin 4 changed to: 0
Pin 4 changed to: 1
Pin 4 changed to: 0
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 1
Pin 4 changed to: 1
Pin 4 changed to: 0
Pin 4 changed to: 1
Pin 4 changed to: 0
Pin 4 changed to: 1
Pin 4 changed to: 0
Pin 4 changed to: 1
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 0
Pin 4 changed to: 1
Note how sometimes the interrupt callback is fired but the value doesn't appear to have changed. This happens because the value rapidly switches (or "bounces") due to noise or mechanical/physical imperfections with the button/connection.
A common approach to "debouncing" is timing the duration between the current interrupt and the previous one. If it's faster than, say, 100ms then the toggle probably wasn't intentional and should be ignored. Here's an example: https://raspberrypi.stackexchange.com/questions/8544/gpio-interrupt-debounce
As a developer I could implement this myself on top of your library, but it would be much easier if that functionality was baked in.
Any change to add I2C to this lib ?
i use a lot of I2C boards and usually i use exec() to control them... is not great but it does the job.
something to work on that would be super.
I suggest we do a new numbered release sometime soon, along with the changes to the language version requirements.
@svpernova09 have you got admin access to the Packagist package btw?
Perhaps it would be a good idea to introduce some PHP7 typehinting, before we do that. It would be a BC breaking change, but we could release the library at version 1.0.0
after this and any other pending changes.
Thoughts?
$pin = $factory->getInputPin($num, $autoExport);
Interested to hear any other thoughts
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.