Well, I thought I had the CRON thing cracked. I made my cron file….. with this inside it..
* * * * * /usr/bin/wget http://127.0.0.1/mqtt/examples/publish.php
And sure enough – CRON runs the PHP page which publishes a couple of topics every minute as it should do, to my MOSQUITTO broker sited elsewhere, exactly as it should do and as does the same PHP page has been doing for weeks on another system.
GREAT… except that every minute it also generates an empty file in /home/pi directory
I am happy to admit… I do not have the foggiest idea why the Raspberry Pi 2 would do this – in fact I have no idea how that PHP page and the home/pi directory are even aware of each other. Any ideas guys?
re the following:
function procmsg($topic,$msg){
global $mqtt;
$status=array(0);
echo “Msg Received: “.date(“r”).”\nTopic:{$topic}\n$msg\n”;
if (strcmp($msg,”on”)==0) system(“gpio write 1 1″); else system(“gpio write 1 0″);
exec(“gpio read 1″,$status);
$mqtt->publish(“procresp”,serialize($status),0);
}
– why is status declared as an array; is it a requirement of the gpio read? btw, this is sufficient to declare an array, if that’s what’s required: $status=array();
– serialize should make a string out of anything; what are you seeing in subscribers from the publish line?
– you can try outputting the array $status to the terminal to view its values: put print_r($status); underneath the exec line
– if you just want one element of the array in the publish data, use a subscript: GPIO 1 would probably be $status[1]
Hi Ken
I can tell you exactly what is coming out… I used serialize as without it I was getting NOTHING out. See below – There is a “0” at the end which becomes a “0” depending on the status. Why declared as an array? That was the example given! The example also shows $status[0] as the output – but it’s not – it returns 0 regardless (and I have a led on the port bit to prove it is turning on and off)
a:2:{i:0;i:0;i:1;s:1:”0″;}
Anyway, THANKS FOR HELP – it turns out that $status[1] does indeed return the result 1 or 0 – so the problem appears to be solved!!! There are only two values [0] and [1] – I just hope this works for the other ports.
My bad. Stupid PHP has wierd scope rules; unlike most other languages, it can’t normally see externally declared variables from within a function.
So, just above the $mqtt->publish line inside that function, put global $mqtt; – like so
function procmsg($topic,$msg){
echo “Msg Received: “.date(“r”).”\nTopic:{$topic}\n$msg\n”;
global $mqtt;
$mqtt->publish(“procresp”,”Got it”,0);
}
This should make $mqtt visible
Isn’t that weird.. but you’re right – it works – just tried it – and thank you so much for that simple explanation.
it would be much wiser to no execute curl or wget at all as its needs quite alot of recources and is not fast at all .. also the apache will create child processes and finally start the php engine to do the job …
you can bypass the whole Network stack the apache processes and the connection times by simply execute the file locally (since its on the same machine anyway)
whith a cron entry like this:
* * * * * /usr/bin/php -f /var/www/mqtt/examples/publish.php > /dev/null 2>&1
this would be alot more effective and definitely faster !
I likely would but it would mean changing links in the publich.php file as they are relative to the website root. Once you start that then every php file is surely going to have to be similarly altered?
there is a Solution for that too ..
execute a .sh file instead via crontab like this:
* * * * * /somewhere/publish.sh > /dev/null 2>&1
/somewhere/publish.sh
#! /bin/sh
WEBROOT = /var/www
cd $WEBROOT
/usr/bin/php -f $WEBROOT/mqtt/examples/publish.php > /dev/null 2>&1
well somethings like that .. guess you get the idea
as for the changes in the php itself …
this depends very much on how the structure is build.
if you have relative paths to the web-root .. you can just use $_SERVER[‘DOCUMENT_ROOT’] to refer to it safely or dirname(__FILE__) to refer to the file itself ..
the best is to define this things in the file itself or in the config like this:
define('ROOT',dirname(__FILE__) . '/');
and then use calls like this (include example, works on all file operations in php
include(ROOT. "someotherfile.php");
It likely would but it would mean changing links in the publish.php file as they are relative to the website root. Once you start that then every php file is surely going to have to be similarly altered?
Once you start that then every php file is surely going to have to be similarly altered?
Can’t answer that without seeing the file, but how complex is your publish.php file?
As per Mario, serving something then accessing it from the same computer carries alot more overhead than simply executing it directly, so, ideally you should only be serving something if it needs to be accessed in a controlled way over the network.
It might take an hour or two with a pad and pencil to plan out such a change, but the result will be faster performance and a much lighter load on the Pi.
Ok so the my issue with that – and reading the various replies I can see why you might want to do this to reduce resources…. in the publish.php I have..
require(“../phpMQTT.php”);
So presumably immediately that address is wrong. I kind of thought the library might have includes which would also fail but it seems not.. but presumably other libraries would all needs various changes where they include files?
Are you running the ‘bluerhinos/phpMQTT’?
If you are using that as organized in the github repo (publish.php is in examples/) that relative path (“../phpMQTT.php”) is valid, whether you’re serving it or running publish.php directly.
I just downloaded the phpMQTT project, changed the url to my MQTT server, used MQTT_spy to subscribe to the test publish, and ran publish.php… and it worked. Give it a whirl on your Pi.
Yes, there’s a subscribe.php page as well and it’s a DOODLE to get it to respond to requests… my kind of simple programming.
Now, given that I have identified a message called “LIGHT4=ON”… can anyone suggest without going around the houses and using scripts talking to databases etc, the easiest way to control one of the port bits in the PI from the PHP program… something like portbit(4,ON); would be nice – or is that asking a lot?
I wonder – so the subscribe page is easy enough – a loop that sits there forever waiting for publications. Do you happen to know, in that subscribe page, if you received an MQTT message and accordingly wanted to send a message back – how you would CALL the publish.php with parameters?
Most of the early programming excitement around the Pi was in python, so there’s lots of stuff online about controlling GPIOs on the Pi in python. But Googling “raspberry pi php gpio” also turns up several resources for GPIO in PHP as well. Note that like the ESP8266, the Pi has 3.3v GPIO levels, so you’ll need buffers or level converters to interface with 5v logic.
WiringPi is a popular C library for the Pi, in the style of Arduino’s “wiring” system, and apparently there’s a port of it to PHP: https://github.com/WiringPi/WiringPi-PHP … so that’s a good place to start I think.
Calling publish from the subscribe loop: once the library’s been included and your $mqtt object instantiated, publishing should be as simple as one line inside function procmsg:
$mqtt->publish($topic, $content, $qos = 0, $retain = 0);
… with desired params. Can’t try it myself til later.
Oh, HAH – I never thought of calling the function itself as against the web page – well done 🙂 Thanks for the info on the PHP port of WIRING. The mechanism I’m using right how has a script watching a database for changes and a PHP page updating the database and.. well, that’s just WAY too slow.
And so that brings me to my limitations in PHP. Looking at the code, I assumed that as I’d declared mqtt in the main body it would be available in the function. NOPE! And so I’ve realised I haven’t the foggiest how that callback is being set up. So, could anyone suggest the modification to this code so that the call to publish does not keel over due to not knowing what mqtt is?
connect(TRUE,NULL,”admin”,”T9quila123″)){
exit(1);
}
$topics[‘pitest’] = array(“qos”=>0, “function”=>”procmsg”);
$mqtt->subscribe($topics,0);
while($mqtt->proc()){
}
$mqtt->close();
function procmsg($topic,$msg){
echo “Msg Received: “.date(“r”).”\nTopic:{$topic}\n$msg\n”;
$mqtt->publish(“procresp”,”Got it”,0);
}
?>
Getting DANGEROUSLY close to having something useful now – but my limited PHP knowledge is once again kicking in.
function procmsg($topic,$msg){
global $mqtt;
$status=array(0);
echo “Msg Received: “.date(“r”).”\nTopic:{$topic}\n$msg\n”;
if (strcmp($msg,”on”)==0) system(“gpio write 1 1”); else system(“gpio write 1 0”);
exec(“gpio read 1”,$status);
$mqtt->publish(“procresp”,serialize($status),0);
}
See that publish – well, what I’d like is for $status to return a 1 or 0 string – but of course that’s not what it’s returning – it is returning an array. Do you know what I need in order to turn extract the return value?
Missed this…
I have no idea how that PHP page and the /home/pi directory are even aware of each other
The cron job is probably running as user ‘pi’ … and /home/pi is that user’s home (or default) directory.
(and… welcome to the Dark Side B-) )
Use “curl” instead of “wget”.
As it happens wget works – but can you give me a little more info – would you use it in EXACTLY the same way (with a URL)… and why?
wget is a simple http client that makes a get request, storing the response. CURL is a more powerful http client, that can make almost any kind of http request (get, post and any other methods).
Need to install it first, if not yet installed:
sudo apt-get install curl
then, just the same as wget:
curl http://127.0.0.1/mqtt/examples/publish.php
WGET is rather a simple tool, that is usually used to download particular resource by HTTP protocol, while cURL is more a developer's tool, to perform any kind of HTTP requests (as well as download a file providing -O param). cURL is a powerful tool, so You later can accept POST or add an authorization and so on. If wget finally works for You with stream redirect
> /dev/null
then, probably You don't need cURL. But when You'll need some other HTTP request method or so on, the cURL will be the exactly what You need.
So, it turns out that curl was already installed – so I replaced all of that with curl and the url – and as you say – it works well – thank you very much.
Can you help. I used LEAFPAD as root to edit the file and save it (the file is simply called CRON and sits in the /etc/cron.d folder). From something I read but never understood, I then entered CRONTAB CRON – as it it were performing some magical spell.. Just what exactly does that do if anything. Can I merely edit the file I’ve called CRON or do I need to invoke crontab spells every time?
Turns out that the CURL replacement (simply CURL and the url) in CRON was not such a good idea. It’s working but when I came back tonight my email inbox was chock full of failed mails..
One of ther responses with numbers changed to protect the innocent… I’m assuming the PI is trying to send an email every time CURL is calling the page. I’ve gone back to the WGET version and the emails are no longer coming in.
So this suggests TWO issues, something wrong with the email setup.. and something wrong with the use of CURL.
Any ideas?
Delivery to the following recipient failed permanently:
pi@raspberrypi
Technical details of permanent failure:
DNS Error: Address resolution of raspberrypi. failed: Domain name not found
—– Original message —–
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
Received: from raspberrypi ([185.15.32.613])
(version=TLSv1 cipher=RC4-SHA bits=128/128);
From: root
X-Google-Original-From: root (Cron Daemon) curl http://127.0.0.1/mqtt/examples/publish.php
d=googlemail.com; s=20120113;
h=message-id:sender:from:date:to:subject:content-type;
bh=nByhp5wbf2VmsbGaiLQi1ooaJucoOSToAnjo818xmXN8=;
b=B7f8joSsdLFgrW7ZSXj7LbOvJslYpjDtM+ITGiE9ZoGldY+Yo7clb4GlDPZIU5OGif
DESLiU3v/SbXwAeucfl0dVryAq9CXJEvOqrj1lM1oV73Pahh4GUIJXh1dArCtflHcbuY
6VTa8wVTAAr85FVjcEeaGIooolizQNGm/SUCWtSf+yjD94O0IZb7lIJexuFgitMXjkqnA
ZXkHSk48WMzpjvooo9zhArKXB4aYFSVUIO/zyrbuDHI+jpJka+KW3OLvhf1YFVyvtpeJ
Dl2sgcbnpzX4HI1DY7VV5z9XRP2YJBXG6T6Pz+Azu3tMK/wexmg7HhNjSG9mz6o6TNoV
4vwg==
X-Received: by 10.194.243.1 with SMTP id wu1mr853119wjc.69.1423688713503;
Wed, 11 Feb 2015 13:05:13 -0800 (PST)
Return-Path:
by mx.google.com with ESMTPSA id hr1sm248788880wib.1.2015.02.119.13.05.09
for
Wed, 11 Feb 2015 13:05:12 -0800 (PST)
Message-ID: <54dbc408.6160b40a.61c4.ffff9e88@mx.google.com>
Sender: Peter Scargill
Received: by raspberrypi (sSMTP sendmail emulation); Wed, 11 Feb 2015 21:05:01 +0000
Date: Wed, 11 Feb 2015 21:05:01 +0000
To: pi
Subject: Cron
Content-Type: text/plain; charset=UTF-8
X-Cron-Env:
X-Cron-Env:
X-Cron-Env:
X-Cron-Env:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 –:–:– –:–:– –:–:– 0
0 0 0 0 0 0 0 0 –:–:– –:–:– –:–:– 0
add ” > /dev/null 2>&1″ to avoid the emails
Aw – THANKS!
Can anyone see what’s wrong with the email setup?? Thanks for the answers incidentally…
the pi send the email to pi@raspberrypi
which is a non existing domain … thats why you get the bounce message
the easiest way to fix this is to set a proper hostname for the pi .. as a email is actually (in the real sense the user on the machine @ the name of the machine … and this is exactly how the mail adress is beeing formulated.
pi is the user and raspberrypi is the name of the computer
okay its 2015 and some times this things do not really work like planned anymore
so you can just add in /etc/crontab
the line MAILTO=your@email
then the cron will send all emails to this one after you restart the service
Ok, sorry to be thick.. there is no etc/crontab directory.
My file is in /etc/cron.d and I called the file cron do I put that command in there somewhere?
I only have one line in that file right now…
* * * * * curl http://127.0.0.1/mqtt/examples/publish.php > /dev/null 2>&1
I can easily remove the dev/null stuff to test the email but not entirely sure where to put the line you suggest.
Also when I’ve edited the file called “cron” – as I don’t know any better, I then run “crontab cron”. Does that actually do anything? I’ve never “restarted” the service knowingly.
/etc/crontab is a file .. not a directory it holds some basic configuration
just open it with the editor of your choice
the command crontab cron will add the file called “cron” to the current crontab
you can see the result by typing crontab -l
The light is coming on.. so what you are saying? Is that my “cron” file in /etc/cron.d doesn’t actually DO anything – it is just a source of info to be added to CRONTAB which is what is actually read every minute?
exactly (thats why i keep this cron-setting files somewhere else)
Lovely.
/usr/bin/wget http://127.0.0.1/mqtt/examples/publish.php
The thing is doing exactly what you’re asking it to… which is to get the webpage you’re asking for. Which it then saves for you.
As per the previous comment, you can simply discard the output from wget
/usr/bin/wget -O - http://127.0.0.1/mqtt/examples/publish.php > /dev/null 2>&1
(translation – send the file from wget to std out, then hey, throw out the std out. Errors too)
But if all you need to do is to simply fire off the php script, you can avoid the load on the webserver and call a php script directly:
php [full or relative path to]/mqtt/examples/publish.php > /dev/null
Again, you can use the redirect to /dev/null to ignore any output from the script… or, if the output is useful you could append it to a logfile.
Cleaner way is to tell wget to save to /dev/null directly (instead of writing to stdout and directing it to /dev/null)
/usr/bin/wget -O /dev/null http://127.0.0.1/mqtt/examples/publish.php
Also note, that by default cron will try to send all output via email, and it tends to build a large queue under /var/spool/mail, if you don’t want it to send any email, add MAILTO=”” to the top of the crontab (cron -e)
Hi Tomer – yes, I finally got that dev/null to work and thanks for the info. I’ve checked /var/spool/mail however and despite that page now being called 2,756 times since last reboot – there’s absolutely nothing in the mail folder….
check also /var/spool/clientmqueue , it might build up there as well.
This might be related:
http://ubuntuforums.org/showthread.php?t=1909905
Pete, this is because wget is built to download files. So what is happening is that it is getting the return of the publish.php file and saving it locally. By default, it does not overwrite the old publish.php file it downloaded, so it just keeps writing a new one every time.
So, you will want to change your cronjob a bit to tell wget to not save the output to a file. I’d recommend checking out this topic at Stack Overflow: http://stackoverflow.com/questions/13259530/using-cron-jobs-to-visit-url
wget -O /dev/null ….
That I believe did it and thanks to those who came up with a similar solution.
Those files named publish.php*, are sucesive downloads by wget. If you just what the cgi to be executed, you could send wget stdout to null, something like:
wget -qO- $url &> /dev/null