More Pi Mysteries

Well, I thought I had the CRON thing cracked.  I made my cron file….. with this inside it..

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

homepi

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?

42 thoughts on “More Pi Mysteries

  1. 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]

    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.

  2. 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

    1. Isn’t that weird.. but you’re right – it works – just tried it – and thank you so much for that simple explanation.

  3. 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 !

    1. 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?

      1. 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

      2. 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");

    2. 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?

      1. 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.

    3. 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?

      1. 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.

        1. 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?

        2. 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?

          1. 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.

            1. 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.

            2. 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);
              }
              ?>

            3. 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?

  4. 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-) )

    1. 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?

      1. 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.

        1. 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?

          1. 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;
            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: Received: from raspberrypi ([185.15.32.613])
            by mx.google.com with ESMTPSA id hr1sm248788880wib.1.2015.02.119.13.05.09
            for (version=TLSv1 cipher=RC4-SHA bits=128/128);
            Wed, 11 Feb 2015 13:05:12 -0800 (PST)
            Message-ID: <54dbc408.6160b40a.61c4.ffff9e88@mx.google.com>
            Sender: Peter Scargill From: root X-Google-Original-From: root (Cron Daemon)
            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 curl http://127.0.0.1/mqtt/examples/publish.php
            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

              1. 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

                1. 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.

                  1. /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

                    1. 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?

  5. /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.

    1. 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)

      1. 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….

  6. 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

  7. 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

Comments are closed.