Values from arduino side parsed in php file on linux side

Hi all,

I have read various tutorials and forum post bust I can't get this to work. What I would like to to is pass on values that I will eventually get from serial input on the arduino side to be processed by a php-file on the linux side.

  • I know for a fact that my php-file is working.
  • For simplicity I have commented out the whole section that should get the values out of the serial input and just used constant values (1-7). Can anybody tell me where I go wrong? Thanks!
/* Arduino 'slimme meter' P1-port reader.
 
 This sketch reads data from a Dutch smart meter that is equipped with a P1-port.
 Connect 'RTS' from meter to Arduino pin 5
 Connect 'GND' from meter to Arduino GND
 Connect 'RxD' from meter to Arduino pin 0 (RX)
 
 Baudrate 115200, 8N1.
 BS170 transistor & 10k resistor is needed to make data readable if meter spits out inverted data
 
 A .php file is requested (with consumption numbers in the GET request) every minute (interval set at line #52)
 created by 'ThinkPad' @ Tweakers.net, september 2014
 
 http://gathering.tweakers.net/forum/list_messages/1601301
 */

#include <AltSoftSerial.h>
#include <SPI.h>
#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

// AltSoftSerial always uses these pins:
//
// Board          Transmit  Receive   PWM Unusable
// -----          --------  -------   ------------
// Teensy 2.0         9        10       (none)
// Teensy++ 2.0      25         4       26, 27
// Arduino Uno        9         8         10
// Arduino Mega      46        48       44, 45
// Wiring-S           5         6          4
// Sanguino          13        14         12
// Yun (Leonardo)     5        13       (none)

//IPAddress server(127,0,0,1);
YunServer server;

const int requestPin =  3;         
char input; // incoming serial data (byte)
bool readnextLine = false;
#define BUFSIZE 75
char buffer[BUFSIZE]; //Buffer for serial data to find \n .
int bufpos = 0;
long mEGLT = 1; //Meter reading Electrics - consumption low tariff
long mEGHT = 2; //Meter reading Electrics - consumption high tariff
long mELLT = 3; //Meter reading Electrics - production low tariff
long mELHT = 4; //Meter reading Electrics - production high tariff
long mEGAC = 5; //Meter reading Electrics - Actual consumption
long mELAP = 6; //Meter reading Electrics - Actual production
long mG = 7;    //Meter reading Gas

long lastTime = 0;        // will store last time 
long interval = 60000;           // interval at which to blink (milliseconds)

void setup() {
  Serial.begin(115200);
  delay(1000);
  Bridge.begin();
  pinMode(4, OUTPUT);                  // SD select pin
  digitalWrite(4, HIGH);               // Explicitly disable SD
  server.listenOnLocalHost();
  server.begin();
  delay(1000);

  //Set RTS pin high, so smart meter will start sending telegrams
  pinMode(requestPin, OUTPUT);
  digitalWrite(requestPin, HIGH);
}

void loop() {

  YunClient client = server.accept();

//  decodeTelegram();

  if(millis() - lastTime > interval) {
    lastTime = millis();   
    //send data to PHP/MySQL
    httpRequest(client);
/*    //Reset variables to zero for next run
    mEGLT = 0;
    mEGHT = 0;
    mELLT = 0;
    mELHT = 0;
    mEGAC = 0;
    mELAP = 0;
    mG = 0; */
    //Stop client
    client.stop();
  }
} //Einde loop

/*void decodeTelegram() {
  long tl = 0;
  long tld = 0;

  if (Serial.available()) {
    input = Serial.read();
    char inChar = (char)input;
    // Fill buffer up to and including a new line (\n)
    buffer[bufpos] = input&127;
    bufpos++;

    if (input == '\n') { // We received a new line (data up to \n) => levering hoog tarief
      if (sscanf(buffer,"1-0:1.8.1(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEGLT = tl;
      }

      // 1-0:1.8.2 = Elektra verbruik hoog tarief (DSMR v4.0)
      if (sscanf(buffer,"1-0:1.8.2(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEGHT = tl;
      }

      //1-0:2.8.1 = Elektra levering laag tarief (DSMR v4.0)
      if (sscanf(buffer,"1-0:2.8.1(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mELLT = tl;
      }

      //1-0:2.8.2 = Elektra levering hoog tarief (DSMR v4.0)
      if (sscanf(buffer,"1-0:2.8.1(%ld.%ld" ,&tl, &tld)==2){
        tl *=1000;
        tl += tld;
        mELHT = tl;
      }
      

      // 1-0:1.7.0 = Electricity consumption actual usage (DSMR v4.0)
      if (sscanf(buffer,"1-0:1.7.0(%ld.%ld" ,&tl , &tld) == 2){ 
        mEGAC = (tl*1000)+tld;
      }

      // Hier moet nog Elektra huidige levering (DSMR v4.0)
      if (sscanf(buffer,"1-0:2.7.0(%ld.%ld" ,&tl , &tld) ==2){
        mELAP = (tl*1000)+tld;
      }

      // 0-1:24.2.1 = Gas (DSMR v4.0) on Kaifa MA105 meter
      if (strncmp(buffer, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0) {
        if (sscanf(strrchr(buffer, '(') + 1, "%d.%d", &tl, &tld) == 2) {
          mG = (tl*1000)+tld; 
        }
      }

      // Empty buffer again (whole array)
      for (int i=0; i<75; i++)
      { 
        buffer[i] = 0;
      }
      bufpos = 0;
    }
  } //Einde 'if AltSerial.available'
} //Einde 'decodeTelegram()' functie*/

void httpRequest(YunClient client) {
  // if there's a successful connection:
  if (client) {
    client.print("GET /www/elekgas/p1.php?mEGLT=");
    client.print(mEGLT);
    client.print("&mEGHT=");
    client.print(mEGHT);
    client.print("&mELLT=");
    client.print(mELLT);
    client.print("&mELHT=");
    client.print(mELHT);
    client.print("&mEGAC=");
    client.print(mEGAC);
    client.print("&mELAP=");
    client.print(mELAP);
    client.print("&mG=");
    client.print(mG);
    client.println(" HTTP/1.1");
    client.println("Host: 127.0.0.1/srv/mysql/elekgas");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();
    //Request complete; empty recieve buffer
    while (client.available()) { //data available
      char c = client.read(); //gets byte from ethernet buffer
    }
    client.println();
  } 
  else {
    client.stop();
  }
}

This is a hack on the code produced by 'ThinkPad' as said in the basic info at top of the code. He got it working, just his server was placed somewhere else so I tried to alter it that it would just use the bridge to reach the Linux-side and not go via the network (although that didn't work either on my Yun).

arjan_hes:
What I would like to to is pass on values that I will eventually get from serial input on the arduino side to be processed by a php-file on the linux side.

Please try describing exactly what you want to do a bit more clearly. From this description, it sounds like you have a PHP file on the Linux side of the Yun, and you want the sketch to periodically call this local PHP file? Is that what you're trying to do? Because your code does nothing even close to that.

Basically, as it is written, your YunServer object ("server") will repeatedly listen for incoming web requests for URLs that look like "http://arduino.local/arduino/xxxx" where xxxx is anything and is passed to the client object. That is what this part of the code is doing:

 server.listenOnLocalHost();
  server.begin();

On each iteration of your loop() function, the server object is checking for an incoming connection, and if there is one, it will return a valid client object. But you never check to see if a connection was established. The server will keep accepting connections, and keep ignoring those connections, until you run out of client resources (which seems to be around 255 connections.) This is the code that is accepting incoming connections, but never checking if a connection was actually made:

 YunClient client = server.accept();

Then, periodically, you will call the httpRequest() function, passing it the client object from the last server.accpt() call. Because you never check to see if there is a connection, and just constantly try to accept new connections, the odds are infinitesimally small that the client object will actually have a valid connection. If by chance, you catch it just right and the timing of an incoming connection is perfect and the client object is actually connected, the httpRequest() function writes out a long series of strings to the client. This looks like you are trying to manually issue an HTTP GET command. However, there is no server listening to that client: odds are there is nothing there, and if there is, it would be an incoming connection from a client trying to make its own request.

Finally, you have this construct in httpRequest():

 if (client) {
// Lots of client I/O code removed for clarity...
  }
  else {
    client.stop();

You are checking if there is an incoming client connection, and if so, you are trying to make a request. But if there is no connection, you are calling client.stop(). There is no need to stop a client that has no connection, you need to stop a client that does have a connection, and you so it when you are done using that connection.

So, you code does nothing like what you describe in your post. Are you trying to accept incoming connections (what your code is almost trying to do), make outgoing connections (what the GET request seems to be doing) or calling a local PHP file (what your post seems to be describing.)

We can give you some help doing any of the three options above, or perhaps something completely different, but first we need to know what you are actually trying to do?

Hi ShapeShifter,

It sounds like I have clearly gone down the wrong path with this.

I am indeed trying to call a php file on the Linux side and pass on the values in the variables mEGLT, mEGHT etc.

As I said, I hacked this code. The original can be found on this page (site in Dutch but code is still arduino, just scroll down).

Maybe I need the Process.h library? I tried a few examples but could it not get to work either.

In short, I try to call that php file with the variables in the address so that it can use the $_GET on the php side to get all the values send by the Arduino side. The address should look like this (more or less):
/www/elekgas/p1.php?mEGLT=1&mEGHT=2&mELLT=3&mELHT=4&mEGAC=5&mELAP=6&mG=7.
Well, all numbers should be generated by the arduino code but you get the idea I hope...

Thanks for your response!

So I have things changed.

it now looks like this in the initial bit:

#include <AltSoftSerial.h>
#include <SPI.h>
#include <Process.h>

// AltSoftSerial always uses these pins:
//
// Board          Transmit  Receive   PWM Unusable
// -----          --------  -------   ------------
// Teensy 2.0         9        10       (none)
// Teensy++ 2.0      25         4       26, 27
// Arduino Uno        9         8         10
// Arduino Mega      46        48       44, 45
// Wiring-S           5         6          4
// Sanguino          13        14         12
// Yun (Leonardo)     5        13       (none)

const int requestPin =  3;         
char input; // incoming serial data (byte)
bool readnextLine = false;
#define BUFSIZE 75
char buffer[BUFSIZE]; //Buffer for serial data to find \n .
int bufpos = 0;
long mEGLT = 1; //Meter reading Electrics - consumption low tariff
long mEGHT = 2; //Meter reading Electrics - consumption high tariff
long mELLT = 3; //Meter reading Electrics - production low tariff
long mELHT = 4; //Meter reading Electrics - production high tariff
long mEGAC = 5; //Meter reading Electrics - Actual consumption
long mELAP = 6; //Meter reading Electrics - Actual production
long mG = 7;    //Meter reading Gas

long lastTime = 0;        // will store last time 
long interval = 60000;           // interval at which to blink (milliseconds)

void setup() {
  Serial.begin(115200);
  delay(1000);
  Bridge.begin();
  delay(2000);
}

And further down the road:

void phpRequest() {
  
  // if there's a successful connection:
  Process p;
  p.begin("/www/elekgas/p1.php?mEGLT='" + mEGLT + "'&mEGHT'" + mEGHT + "'&mELLT'" + mELLT +"'&mELHT'"+ mELHT +"'&mEGAC'"+ mEGAC +"'&mELAP'"+ mELAP +"'&mG'"+ mG +"')");
  
  p.run();
}

It gives me the following error:

Arduino: 1.6.6 (Windows 7), Board:"Arduino Yún"

C:\Users\Arjan\Documents\Arduino\P1_logger_3\P1_logger_3.ino: In function 'void phpRequest()':

P1_logger_3:151: error: invalid operands of types 'const char*' and 'const char [9]' to binary 'operator+'

   p.begin("/www/elekgas/p1.php?mEGLT='" + mEGLT + "'&mEGHT'" + mEGHT + "'&mELLT'" + mELLT +"'&mELHT'"+ mELHT +"'&mEGAC'"+ mEGAC +"'&mELAP'"+ mELAP +"'&mG'"+ mG +"')");

                                                   ^

exit status 1
invalid operands of types 'const char*' and 'const char [9]' to binary 'operator+'

Any clues as this is my first time using Process.h?

Little note: there are some examples about which use python but I never used python. I know my php file works so I would like to keep it if I can...

I started replying to this early this morning, but needed to do a bit of research before actually posting the reply, and also needed some time to deal with some interruptions. It's now mid-morning by the time I get back to it (at least here, odds are it's much later in the day for you) and I see you have posted an update. It invalidates some of what I wrote, but most of it should still be useful.

I'm not going to try and fix your compiler issue, since that code as you have it is heading down a dead end: either we will keep the GET syntax you are trying to duplicate, in which case we won't be using Process, or we will use a completely different syntax if we end up using Process.

But first:

arjan_hes:
Little note: there are some examples about which use python but I never used python. I know my php file works so I would like to keep it if I can...

Do you want to keep the PHP code because you understand PHP and want to keep maintaining/improving it? Or is it because you are afraid to touch the PHP code? The reason for this question becomes clear when you get near the end of my original draft, which is:

Yes, Process is probably the way to go.

But it won't work directly with the PHP code you have, which is set up to react as a web service. The GET string you posted is designed for a web server. It takes that string, processes it, and then calls the PHP code, passing the data as a set of environment variables which the PHP code then reads using the _GET() statements. We can make this code work as-is, with a little bit of effort, by using the web server on the Linux side, and making a web call to the local server. In this case, we wouldn't use the Process class, or at least not directly. We could possibly use the httpClient class to access the local web server, or use the Process class to make a Linux curl call, which access the local web server. In either case, the local web server would then receive the GET string, parse it, pass it to PHP, take the output from PHP, wrap it up in a web page, and then return it. That's a lot of extra work which is needed in the original implementation since the PHP code was on a different computer, but it is a lot of extra overhead with the Yun.

Or, the PHP code can be changed to use command line arguments instead of web GET variables - this would greatly simplify the calling sequence, allowing us to use the Process object with a simplified calling sequence. It takes the web server out of the picture, and make things much simpler and more efficient.

The original code was written to make calls from a lower power Arduino to a more powerful web server. But you are dealing with a Yun that is much more powerful than your typical Arduino. If we look at the problem with the Yun's unique capabilities in mind, we can make the system better and much more efficient.

Is your goal to get that exact PHP code working? Or is it to accomplish the same work that it does?

That is the end of what I originally wrote (with a few updates.) You mentioned that you want to keep the PHP file, but my last question above still stands: is it because you like the PHP code and want to keep it and make future changes to it, or because you are afraid to touch it?

I understand you are new to programming. If you know PHP well and want to stay with it, that's a good enough reason to stay with the PHP code. But if you don't know PHP, and would have to learn it, your time might be better spent learning some Python instead. PHP is great for creating dynamic web pages, but I think Python will serve you better as a general purpose programming language.

Any way you look at it, some code somewhere will need some significant changes. You've already made lots of changes to the sketch to try to accommodate the PHP code. Do you want to make more changes just to keep the PHP code, and still probably need to make PHP changes? Or are you willing to learn something new in order to end up with a simpler, more elegant, and much more streamlined system?

The way I see it, the PHP code is taking the arguments you provide, doing a few SQL updates/queries, and few simple math checks. If you move to Python, you significantly simplify the calling sequence, and keep the SQL pretty much as is without changes. The math checks are simple to translate.

I've used Google to translate the link you provide. The translation is a little rough, but it looks like it is good enough. I'm starting to read it to understand more of what he's trying to accomplish. I'm willing to study it, if you are willing to learn something new to make an efficient solution that fit's the Yun's unique abilities. Or do you just want the minimum changes to get this to work without really learning anything? (In other words, is your goal just to have a working device, or are you also trying to learn something along the way?)

If I were starting this project from scratch, I would use a Python script to take the values and update the SQL database, and use the Process class to call that script. In the end, it will be much simpler and easier to understand.

To give you an idea of what I'm thinking...

If the Linux side script can read command line arguments (trivial for Python, shouldn't be too bad for PHP although I've never tried it) then the sketch code becomes something like:

 Process p;
  p.begin("/mnt/sda1/smartMeter.py");
  p.addParameter(String(mEGLT));
  p.addParameter(String(mEGHT));
  p.addParameter(String(mELLT));
  p.addParameter(String(mELHT));
  p.addParameter(String(mEGAC));
  p.addParameter(String(mELAP));
  p.addParameter(String(mG));
  p.run();

This will run the script named smartMeter.py, which is stored on the SD card at /mnt/sda1, and pass it the list arguments. They are converted to String using the String() constructor, since addParameter() only accepts Strings (an unfortunate limitation, it would've been nice to have included support for other types as well.)

Then, in the Python script, these arguments are read by:

import sys

mEGLT = sys.argv[1]
mEGHT = sys.argv[2]
mELLT = sys.argv[3]
mELHT = sys.argv[4]
mEGAC = sys.argv[5]
mELAP = sys.argv[6]
mG = sys.argv[7]

Then, it becomes a matter of doing the math checks to ensure valid data, and the SQL updates. sonnyyu has a simple example of writing to SQL from Python here: http://www.ibuyopenwrt.com/index.php/8-yun-compatible/89-python-and-sqlite3

I can offer you more guidance if you want to go down this path.

If you are firm on your use of the PHP code, it can be modified to use command line arguments. You would use the Process class in the same way as above, except that you would use the local name of the PHP file instead of the Python file. You would then need to modify the PHP to get the variables from the command line arguments instead of from the web page GET environment variables. It would be something like this (although I've not personally tried it):

$mEGLT = $argv[1]
$mEGHT = $argv[2]
$mELLT = $argv[3]
$mELHT = $argv[4]
$mEGAC = $argv[5]
$mELAP = $argv[6]
$mG = $argv[7]

However, note that the above list of assignments match the list of parameters passed in the Process object call. It's not necessary for the names on the Python/PHP side to match the names of the parameters, as they are passed by position, not name. (But it's still a good idea to use the same names to prevent confusion.) The first parameter will be read by argv[1], the second by argv[2], and so on. Note that this is different than the _GET method currently used in the PHP code which matches parameters by name, not position.

There is a disconnect between your sketch and the PHP code. Even if we get the PHP code working by going through a web server, using your original GET request and the original PHP code, there will be a problem. Your sketch is sending the values using the parameter names:

  • mEGLT

  • mEGHT

  • mELLT

  • mELHT

  • mEGAC

  • mELAP

  • mG
    While the PHP code is trying to access these parameters:

  • mEVLT

  • mEVHT

  • mEAV

  • mG
    The only parameter that is the same in those lists is mG - that value will be passed through, while the remainder of the parameters accessed by the PHP script will not be found, and the rest of the parameters passed by your GET call will be ignored.

Wow, thanks for your effort of explaining all this!

At the moment I have gone down the road of rewriting the code on the arduino (althoigh it's faulty) and also rewrite the php script zo it now matched all the parameters. I am familiar with php. It does work and places the data either in the 'correct values' table or the 'faulty values' table.
I just thought it would be an easy fix, replacing the webserver by the linux side as the Yun can be used as a server as well but clearly I was wrong.

So here is the deal. In the future I would like to have one or two more arduinos (uno w. ethernet?) sending data to the mysql database. If this can be all processed on the Yun (linux side) than I would very much like to do some python. It would take some time to get it figured out but I must admit it doesn't look too complicated (maybe it is though). Also, one is never to old to learn something new! I am a big fan of simplifying things as it makes future projects more easy to integrate I guess.

I do think of buying a NAS in the future (read next year) but I don't necessarily want the mysql database on that. It can remain on the Yun.

So if the above question can be answered with yes, I can connect via the local network more arduinos and have them send data to the mysql database, it sounds like learning (some) python is ultimately the better option.

On top, I specifically bought a Yun because of its unique capabilities. Despite the plans for a NAS I still wanted to explore the yun and that automatically means learning new stuff!
Otherwise I might as well go for the NAS and 'regular' arduino with ethernet which onmits the need for a yun all together; just not the point.

Maybe I should have started with a simpeler program though :smiley:

arjan_hes:
I am familiar with php.

Then there is a good reason to stick with PHP, at least for now.

It does work and places the data either in the 'correct values' table or the 'faulty values' table.

How are you currently testing the PHP code? Exactly how are you calling it? If you are calling it from a command line, then that is what we need to emulate in the Process class call. If you are calling it through a web service, then you have done more work on this than I had assumed.

I just thought it would be an easy fix, replacing the webserver by the linux side as the Yun can be used as a server as well but clearly I was wrong.

You are not wrong about the Linux side of the Yun being able to act as a web server. It can. And you can access the web server from the sketch, just not the way you've been trying so far.

If you are dead set on accessing the PHP script through the web server, we can do that, but it's a bit like writing a note to your wife, putting it in an envelope with a stamp, and putting it in the post box so that it gets delivered back to your house so she can read it. That works, but wouldn't it be more efficient to just hand the note to your wife directly?

In the future I would like to have one or two more arduinos (uno w. ethernet?) sending data to the mysql database. If this can be all processed on the Yun (linux side) than I would very much like to do some python.

This is certainly possible, using either PHP or Python. It's quite simple using Python and some of the application frameworks that are out there (I've been dabbling with the Bottle framework, and have been able to get a rather useful set of dynamic pages running in a short time.) But if you are familiar with PHP, and would rather use that route, it will also work. There are also a lot of other languages and techniques that will work.

To get this working as a web service that can be accessed by the local sketch, and by other (future) nodes, you have to set up PHP as a web service on the Yun. (I don't know if you've already done this?) sonnyyu has some notes on doing that here: ibuyopenwrt.com

The goal at this point is to make sure you can submit data from another computer, such as from a web browser. In an effort to learn a bit more about PHP on the Yun (I've used PHP a little bit on a full featured web server in the past, but never on the Yun) I've tried these steps. Taking little baby steps, working on one part at a time, it shows promise...

  1. I followed sonnyyu's instructions for setting up a PHP web service. The goal at this point is to get an incoming web request to run a PHP file. I did the steps he mentions (he doesn't mention that you may have to run "opkg install nano" to get the nano text editor) and used a web browser on my computer to access http://yun4.local/phpinfo.php -- it worked! (yun4 is the name of the Yun I am using for testing this.)

  2. Next, I then tried a simple test passing GET parameters to PHP.

/www/phptest.php:

<?php
echo "PHP parameter test
";
$value1 .= $_GET["val1"];
$value2 .= $_GET["val2"];
echo "The first value is: ";
echo $value1;
echo "
The second value is: ";
echo $value2;
?>

Using a web browser to access http://yun4.local/phptest.php?val1=Just&val2=Testing, I got the expected output:

PHP parameter test
The first value is: Just
The second value is: Testing
  1. The next step is to do that from a sketch. I started with the HttpClient Example, and made only a slight change, changing the URL on line 40 to:
 // Make a HTTP request:
  client.get("http://127.0.0.1/phptest.php?val1=Just&val2=Testing");

This will access localhost, and pass it the same request as I used with the web browser. It worked! The text that echoed was the same as what I saw on the web browser (except that the SerialMonitor does not parse HTML, so the
tags came through as plain text.)

PHP parameter test
The first value is: Just
The second value is: Testing

I wrote too much, and it complained the post was too long, so I had to break it up. Continuing the discussion from the previous post:

So, assuming you have your PHP code working as a web service (you can manually enter a URL in a web browser and have it save the data) the sketch changes to access the web service directly are minimal:

void phpRequest() {
  HttpClient client;

  // Make a HTTP request:
  client.get(String("http://127.0.0.1/elekgas/p1.php?mEGLT='") + mEGLT +
         String("'&mEGHT='") + mEGHT +
         String("'&mELLT='") + mELLT +
         String("'&mELHT='") + mELHT +
         String("'&mEGAC='") + mEGAC +
         String("'&mELAP='") + mELAP +
         String("'&mG='")    + mG +"'");
}

Note that this is very similar to the latest version you have using the Process class, but there are some important changes:

  • The URL is expanded to include the http header and the localhost address ("http://127.0.0.1/")
  • The /www/ is removed from your Process version. This is assuming that the PHP file is named p1.php, and is stored in /www/eleckgas on the Linux partition. The www portion of the Linux path is assumed and should not be included in the URL.
  • Your parameter list was missing the "=" between each parameter name and the argument
  • The String() constructor is explicitly added to each character string to make the code compile and use the concatenation and type conversion operates of the String class.

So, now we can look at the compile problems you were getting when you tried to use the Process class. The issue is that in C++ there are strings and Strings. The capitalization is important:

  • strings are arrays of characters, where the variable is actually a character pointer pointing to the first character of the string, and the end of the string is indicated by a NULL character in the array. This is the same character sting mechanism that is used in plain C.
  • String is a C++ class that manages an internal representation of a string. It hides many of the arcane details of handling strings, and includes methods to easily concatenate Strings together and also convert variables of other types to Strings so that they can also be concatenated.

In your latest code, you didn't include the String constructor around your character strings, so they were simple character arrays. The compiler looked at the first string ("/www/elekgas/p1.php?mEGLT='") and considered that as a character pointer to an array of strings. It then took your next parameter (mEGLT) and added that to the character pointer. In this case, pointer arithmetic of a long integer added to a character pointer makes syntactic sense, and has the result of moving the character to which the pointer points. In this case, mEGLT has the value 1, so the pointer was incremented by 1, so it moved it to be pointing to the next character in the string, so now you have the string "www/elekgas/p1.php?mEGLT='" (note how the leading "/" is now gone.) Next, you are taking that character pointer, and adding the character array "'&mEGHT'" to it. Plain strings do not have a concatenation operator, so the compiler thinks you are trying to numerically add a character array to a character pointer, and it doesn't know how to do that. That's what it's trying to say in the message.

By converting each string to a String by wrapping it with the String() constructor, you now have the overloaded "+" operator that you can use for string concatenation. There are many other ways to accomplish the same result. Normally, I don't like using Strings, as they bring in a bunch of overhead and have been know to have memory leaks in the past, but the httpClient class and Bridge library make extensive use of Strings internally, so the damage is done, and using String() is an easy way to make the long combined string that you need.

If you go through the baby steps above, you should be able to get it working this way. (I wouldn't skip ahead to the end, because if it doesn't work, you don't know why. If you take it in small steps and make sure each step works, then you know any problems are caused by the latest part you are trying to get to work.)

Now, by giving this, I'm reversing myself from what I was saying before. This is a simple code change, and lets the PHP code work unchanged, but it's a rather inefficient way of doing things. While accessing the PHP code directly and not going through the web server would be more efficient, doing ti this way has merit in your case. The thing that changed my mind was your statement that you will be adding additional nodes that will remotely access the web services of the Yun. Doing it this way lets you use the same mechanisms for both local and remote access: you won't have to do it one way for local use and another way for remote use.

To use another Yun as the remote node (let's call it YunA) and have it connect to this Yun running the PHP services (let's call it YunB) then you would use the same httpClient code on YunA, and the only thing you would change is to use YunB's IP address in place of 127.0.0.1.

To use an Uno with an Ethernet shield as the remote node, you would basically use ThinkPad's original code you started with, changing the server IP address to the Yun's address, and dropping the "www/" from the beginning of the URL in the GET request.

arjan_hes:
I specifically bought a Yun because of its unique capabilities.

The key word in your sentence is "unique." The Yun is unique in it's abilities, and it requires a different way of thinking compared to the more traditional networking solutions that have been spliced onto traditional Arduinos. And with any new way of thinking, there is a learning curve.

Despite the plans for a NAS I still wanted to explore the yun and that automatically means learning new stuff!

Leaning new things is great! We should never stop learning. In fact, I thank you for this thread, as it got me to explore the PHP capabilities of the Yun's web server, and now I don't have to be afraid of considering using PHP in the future if needed.

Maybe I should have started with a simpeler program though :smiley:

What's the fun in that? The traditional way to start is by blinking an LED - that gets old very quickly! If you don't set goals for yourself that are beyond your reach, you won't learn anything new along the way.

I'm away from my computer now for a few days. Just wrote a whole reply on my phone bit it decided to ditch it when I hit post.

In a nutshell:
Go to a browser and type 192.168.0.13/elekgas/p1.php?mEGLT=1... Etc was working in both tables (so math worked as well)

I went busy and created a p1.py file and got it somewhat working via sunnyyu's tutorial. No values were passee to the mysql db though.

I think I need to make a decission as I am eating up your valueble time swithing between py and php :wink:
For my own learning curve I think I try to make both working. Like you said. It's great learning new stuff!

I get back when I am back at my laptop! Approx 4 days. Thanks for your help so far! Great support. I am greatfull for that!

By the way, I totally agree that 'sending a postcard to your own wife' is somewhat over the top. Too much processes and routes.

The other nodes won't pass the same info in the same table but will require a new php file for a different set of data. One way or the other, we'll get it to work :wink:

I shall try that httpClient next and simultanious work on the py script (both when back at the laptop)

Ta

arjan_hes:
Just wrote a whole reply on my phone bit it decided to ditch it when I hit post.

Don't you just hate it when that happens? You can try re-writing the post, but it never seems to be as good as the one you lost...

For my own learning curve I think I try to make both working. Like you said. It's great learning new stuff!

I would take the easy way and get the PHP code working with the httpClient first. Let's make some real progress so that it doesn't get discouraging.

Then, with that working, the pressure will be off, and you can start optimizing it and learning new techniques.

arjan_hes:
By the way, I totally agree that 'sending a postcard to your own wife' is somewhat over the top. Too much processes and routes.

Normally, that would be true. But if it's part of a bigger picture where you are sending a lot of postcards to different people, it just might be easier to print out one more for her and send it with the rest, rather than to make a special version just for her and hand-deliver it. It's all about the big picture and what is less work overall.

The other nodes won't pass the same info in the same table but will require a new php file for a different set of data. One way or the other, we'll get it to work :wink:

Yes, but with the "send a postcard" method, you only have to implement one way of handling requests on the Yun. That's why I reversed my stance once you gave additional information.

Good luck! And keep us posted on your progress when you get back to it. And don't worry about my time, I'm enjoying this and learning something myself.

Command-line PHP & MySQL for Process Class

PHP APIs and MySQL

At Yun/Yun Shield, there are three PHP APIs for accessing the MySQL database. users can choose between the mysql extension, mysqli, or PDO_MySQL.

Plan B:

Official PHP bridgeclient:

PHP Bridge class

arjan_hes:
...
As I said, I hacked this code. The original can be found on this page (site in Dutch but code is still arduino, just scroll down).
...

Arduino code:

#include <Ethernet.h>

It (Arduino code) is designed for ethernet shield, Useless for Arduino Yun/Yun Shield.

Back on it!

ShapeShifter:
Don't you just hate it when that happens? You can try re-writing the post, but it never seems to be as good as the one you lost...

Exactly! You try to write it a second time and although you think you have it rewritten as it was, it still doesn't look similar and is not as good as the first attempt!

Back to the code now (which is the 8th attempt?!)

I did all the baby steps and gotten the exact results as the posts above. So that works fine. I went busy with debugging some of the PHP. I printed everything that is comming in over the serial monitor when we send the client.get command. Turned out I was missing a ' here and there and getting the values it didn't like $mEGLT .= $_GET["mEGLT"]; so I had to get rid of every point in front of the = sign. It now doesn't spit any errors anymore BUT it only returns 0. In fact a total of 7 zeros which is the number of values we are trying to get across.

If I have everything printed straight from the arduino code into the serial monitor it reflects whatever values I set in the variable. When I echo that PHP values, it only prints 0000000. Something is not passed on somewhere.

So on we go with debugging. If I not convert anything in the PHP file to Integer, the serial monitor spit out this:
'3''4''5''6''7''8''9'
So somehow it produces a little too much '. If I get rid of all the '-signs, it goes back to printing all zeros (0).

Getting really close but not quit there yet!

sonnyyu:
Command-line PHP & MySQL for Process Class

PHP APIs and MySQL

At Yun/Yun Shield, there are three PHP APIs for accessing the MySQL database. users can choose between the mysql extension, mysqli, or PDO_MySQL.

Looked at the example and will try this one as well!
Bet time for now, tomorrow is an early start for me.

If you have made changes, your best bet is to post the current code.

ShapeShifter:
If you have made changes, your best bet is to post the current code.

Completely forgotten. Sure it was bedtime for me!

Here's what I have now in the sketch:

#include <AltSoftSerial.h>
#include <SPI.h>
#include <Bridge.h>
#include <HttpClient.h>

...

void phpRequest() {

  HttpClient client;
  
 // Make a HTTP request:
  client.get(String("http://127.0.0.1/elekgas/p1.php?mEGLT='") + mEGLT +
         String("'&mEGHT='") + mEGHT +
         String("'&mELLT='") + mELLT +
         String("'&mELHT='") + mELHT +
         String("'&mEGAC='") + mEGAC +
         String("'&mELAP='") + mELAP +
         String("'&mG='")    + mG +"'");

while (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
  Serial.flush();

  delay(5000);
    
}

Last part obviously for debugging purposes.

The php file looks like this now:

//GET variables
$mEGLT = $_GET["mEGLT"];
$mEGHT = $_GET["mEGHT"];
$mELLT = $_GET["mELLT"];
$mELHT = $_GET["mELHT"];
$mEGAC = $_GET["mEGAC"];
$mELAP = $_GET["mELAP"];
$mG = $_GET["mG"];

/*convert GET-variable to 'integer'
settype($mEGLT, "integer");
settype($mEGHT, "integer");
settype($mELLT, "integer");
settype($mELHT, "integer");
settype($mEGAC, "integer");
settype($mELAP, "integer");
settype($mG, "integer");*/

....

echo $mEGLT;
echo $mEGHT;
echo $mELLT;
echo $mELHT;
echo $mEGAC;
echo $mELAP;
echo $mG;

The 'convert to integer' part is blocked out for now, to see exactly what the values of the variables are. These are echo on the bottom of the code which I am able to see in the serial monitor which in turn produced the results from my previous post, being '3''4''5''6''7''8''9'. If I unblock the 'convert to integer' part, I get printed in the serial monitor 0000000.