Go Down

Topic: Arduino-Yun Wifi - Internet Commands? (Read 7330 times) previous topic - next topic

ShapeShifter

Try explicitly giving the full path to curl. Inside runCurl(), change the p.begin() call to:

Code: [Select]
p.begin("/usr/bin/curl");

The command shell will normally search for the right executable on the path, but here you are not using a command shell and calling the file directly. It may be that it can't find the executable file.

If you had used p.runShellCommand(), then it would launch a command shell, which would then search for the file, and execute it. Instead, you are using p.run(), which does not launch a command shell. Since we already know the location of the curl command on the system, and don't need the command processor's help, there is no need to add the extra overhead of runShellCommand() - I think run() is the proper choice in this case.

If that doesn't work, put in a loop that echos the output from the command. It's probably returning an error string that might give a good clue to the problem:
Code: [Select]

 while (p.available()>0)
 {
   char c = p.read();
   Serial.print(c);
 }


Of course, you will need to call Serial.begin() in setup().

In looking at your code, you are calling runCurl(), any time that the button is high. Done this way, runCurl() will likely get called multiple times when the button is pressed, and will keep getting called over and over again as long as the button is pressed. It doesn't matter if you turn on the LED thousands of times while the button is pressed, but you probably don't want to be inundated with countless notifications for each press.

Take a look at the Debounce Example and try to understand what it is doing. You will almost certainly need to do something similar. You will want to call runCurl() where the example code is toggling the LED state.

stgeorge

Thanks

Re-Debounce- I'm sure that is going to be a problem that I'll need to deal with, but I'm trying to stay focused here first to get it actually working, plus that debounce (toggle on/off) was hurting by brain looking at, so for now, I'm putting that on the back burner.  I agree though, once I get this working, I'm going to need a simple, effective way to just shoot one call out every time it is actually pressed.

So, I replaced "curl" with the "/usr/bin/curl" and connected the pin (i.e. pressed the button), and nota.

For the echo - do I put the while statement just below runCurl(); in the loop and yes, call Serial.begin() in setup...is that all? 

Also- why #include <Bridge.h> and <Process.h> at the start- I sort of figured that needed to be there, but I don't really understand what they are doing.

Thank you



stgeorge

#32
Aug 17, 2016, 06:54 pm Last Edit: Aug 17, 2016, 07:03 pm by stgeorge
Also- the first draft yielded the following on Serial.begin();


no matching function for call to 'Serial_::begin()'

I think I'll need to add 9600 baud rate?

Also- p.available needs to be called out ahead someplace, right?  It's getting hung on that too.

Thanks

ShapeShifter

I agree though, once I get this working, I'm going to need a simple, effective way to just shoot one call out every time it is actually pressed.
The issue is that you are probably going to be making a bunch of calls, one right after the other, and that could possibly cause issues that would not show up if you just made a single call. As a compromise until you get proper debouncing working, you could add a delay() call immediately after calling runCurl(). For a "production" system, this would not be a good thing, but as a quick proof of concept it should work. If you add a delay(1000); after the runCurl() call, then it will call the function only once if you press the button less than a second, and will call it once a second if you hold the button down. You could make the delay longer if you want to make sure it's only called once for a longer press. But this delay will tend to make the program unresponsive, so you don't want it to be longer than necessary.

Quote
So, I replaced "curl" with the "/usr/bin/curl" and connected the pin (i.e. pressed the button), and nota.
Well, it was worth a try.

Quote
For the echo - do I put the while statement just below runCurl(); in the loop and yes, call Serial.begin() in setup...is that all?  
No, put it inside runCurl() after the p.run() call. If you put it outside of runCurl(), the p object will not be defined. Not only will this cause a compile error, but even if you could call it from there, the p object will be automatically destroyed when runCurl() exits, along with any data you would be trying to read.

Quote
Also- why #include <Bridge.h> and <Process.h> at the start- I sort of figured that needed to be there, but I don't really understand what they are doing.
Those files define the Bridge and Process classes, respectively. It's telling the compiler that the classes exist, and what their interface is - the functions and data that the class provides. This lets the compiler check that you are calling any functions properly, and it tells the compiler how to generate the proper code to call those class functions.

Without those include statements, it won't know about the Bridge object and how to call Bridge.begin(), and it won't know about the Process class and won't know how to create the p object of that class, nor what functions can be called in that class.

I think I'll need to add 9600 baud rate?
Yes, you will need to add some baud rate, and it generally must match what you are using in the Serial Monitor. The exception is when the USB port is managed directly by the AVR chip, like when using a '32U4 processor that is on a Leonardo, Pro Micro, or genuine Yun board - in that case, the baud rate is meaningless and can be anything, but something must still be provided.

Quote
Also- p.available needs to be called out ahead someplace, right?  It's getting hung on that too.
You probably went ahead and put the p.available() loop in your loop() function after calling runCurl(). The compiler does know about the available() function as it applies to the Process class (because you did the #include of Process.h.) What it's no doubt complaining about is that it doesn't know what the "p" object is. Inside the runCurl() function it's defined to be an object of the Process class, but that variable declaration does not extend outside of the runCurl() function. Therefore, the compiler doesn't know what type it is, doesn't know that it's a Process object, and therefore doesn't know that the available() function is available for that object.

The answer is to put that available loop at the end of runCurl(), after the p.run() command, and before the function's closing curly brace.

stgeorge

#34
Aug 17, 2016, 10:45 pm Last Edit: Aug 17, 2016, 10:56 pm by stgeorge
Well...fits & starts I guess.  I made those various changes (see below), and it compiles fine, but not only does it not make the 'call' to the website, now it doesn't even light up the LED when I 'press the button' ?!

Maybe you can look and see what I've done wrong?  I can't get the serial monitor to connect either, so I have no idea.

I do think that delay idea is a good one temporarily- in fact, I thought it was possible that due to multiple calls, the website wasn't reacting, so I put in a 1200 ms delay and nope.

Anyway- here's what I have currently...

// set pin number:
const int buttonPin = 3;     // the number of the doorbell input
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

#include <Bridge.h>
#include <Process.h>

void setup() {
   // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  Bridge.begin(9600);
  Serial.begin(300);
}

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
    runCurl();
    delay(1200);
 
  } else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }
}

void runCurl() {
 Process p;           
 p.begin("curl");
 p.addParameter("-d");
 p.addParameter("\"devid=vBECBF1F4A7D765\"");
 p.addParameter("http://api.pushingbox.com/pushingbox");
 p.run();
 while (p.available()>0)
 {
   char c = p.read();
   Serial.print(c);
 }
}

ShapeShifter

This doesn't look right:

Code: [Select]

  Bridge.begin(9600);
  Serial.begin(300);



Bridge.begin() is normally called with no arguments. It can be called with a single numeric argument, like you now have it, and that would be the baud rate that the serial port talking to Linux should use. It's there in case you have a special requirement to use a different baud rate. But you can't change it here unilaterally - if you provide a custom baud rate here, you need to go into Linux and change the baud rate there as well. If you change it only in the sketch, then the two processors will not be able to talk to each other. Bridge.begin() will not be able to establish communications with the Linux side, and it will likely never return. This is probably why your LED is no longer working, because Bridge.begin() has not returned while it tries over and over again to establish communications.

Then, you have the baud rate in the Serial.begin() call. 300 baud is a valid speed, but it is very slow. I doubt you really want to use that low of a speed. The only reason to do so is if you have a VERY long serial cable (hundreds of feet?) or you are using a dial-up acoustic coupler modem (has anybody used them in the last 40 years or more? The last time I used 300 baud was in the mid-'70s with an acoustic coupler - where you manually dialed the telephone and placed the phone handset in the rubber cups of the modem. This was when ARPAnet, the precursor to the Internet, only had about a dozen computers connected to it, and I had to dial into Rutgers to get onto it, because my university wasn't connected directly.)



Cool!  I found a picture of the same Anderson Jacobson modems I used in the '70s. 8)
Talk about a trip down memory lane...


Anyway, back to the topic... I think you need to take the parameter out of the Bridge.begin() call, and use a more appropriate value for Serial.begin(), like 9600, 19200, or 115200.

ShapeShifter

BTW, please use code tags when posting code. It makes it much easier to read, and prevents silly formatting issues that can sometimes happen.

There are two ways:
  • Click on the </> button that is immediately above the reply edit box. That will insert the code tags, and put the cursor in the right spot between the tags where you can paste your code
  • In the Arduino IDE, select all of your code, then use the Edit | Copy for Forum menu option. Then, just past the code into your post. The Copy for Forum command copies your code and automatically adds the code tags.

stgeorge

OK- yes that's quite a trip!  Interestingly though, when the Arduino IDE's serial monitor pops up, the default rate is 300 baud ?!  So that's why I chose it for the Serial call and as far as the bridge, I thought you had said that I should call out some baud, but it doesn't really matter since I'm using an underlying Leonardo board- but I had seen someplace else online where they recommended 115,200 so that's what I used.  Oh well...let me try nothing for the Bridge begin call and 9600 for the serial call and I'll report back...

stgeorge

OK- so I changed the Bridge.begin call to () and the Serial.begin call to (9600) and now the led light is indicating a 'pressed button' so that's good, but still no serial communication and definitely no runCurl command execution...ugh!

Not sure exactly what you mean by "code tags" ?  I guess I'm slow, but don't follow that one...

ShapeShifter

You're right, when using a Leonardo the baud rate makes no difference: either in Serial.begin or in the Serial Monitor. There are a couple recent Yun Shield discussions going: one using a Leonardo, and one using a Mega2560 - and I couldn't immediately remember which one you were using.

Interestingly though, when the Arduino IDE's serial monitor pops up, the default rate is 300 baud ?!
I'm guessing you changed it at some point in the past and forgot about it. When the Serial Monitor opens, it remembers the settings you had used last time.

One thing to be aware of with the Leonardo is that the USB serial port is created by the sketch software itself. Every time you load new code, or reset the Leonardo, the serial port goes away briefly, and then appears again. I found that I generally have to close and reopen the serial terminal emulator to see any output every time that the sketch restarts. That may be what is happening here: try starting the sketch, and THEN open the Serial Monitor and see if that makes any difference. That's why so many example sketches have this:

Code: [Select]
while (!Serial)
   ;


When converted to a boolean, Serial will initially be false until a USB serial connection is made. Since the while loop checking this does nothing (has just an empty semicolon) the sketch will wait until a connection is made. This is because on these systems, the connection cannot be established until after the sketch starts and Serial.begin() has been called. This construct is used when setup() wants to print out some initial information that you want to capture on the Serial Monitor. By waiting for a connection, those initial messages aren't printed out before there is a chance to make a connection.

That's not really a concern in your case, since there are no other messages printed at startup. The only thing you're looking for is any messages printed when you press the button.

Not sure exactly what you mean by "code tags" ?  I guess I'm slow, but don't follow that one...
Read this...

stgeorge

Very educational and helpful- thanks!  I'll try to improve my posts going forward   :smiley-grin: .

One thought I had overnight was that, the *only* time I've actually seen the serial monitor work properly has been when I have run the ConsoleRead example sketch.

Again, since I'm going over wifi, I wonder if it wouldn't make sense to replace all the serial monitor stuff with console read stuff and give that a try.  If it works, I'd be able to actually see what the mcu is doing and/or if there are any errors when it attempts to run this curl command.

I can go back and look at that ConsoleRead sketch and see if I can figure out how to replace the serial monitor coding with console coding, but if you have any thoughts on this either way and/or if you have any advice as to console coding requirements, please let me know.  Thanks.

ShapeShifter

Again, since I'm going over wifi, I wonder if it wouldn't make sense to replace all the serial monitor stuff with console read stuff and give that a try.
I don't think you mentioned that you were trying to use the Serial Monitor over WiFi, or if you did, I missed it. Yes, if you are using a strictly WiFi connection, you MUST use the Console class. The Serial class works ONLY over the USB serial connection. The Console class works ONLY over a network connection (WiFi or Ethernet.) The fact that we were talking about the Serial class made me assume we were talking about USB.

Quote
...see if I can figure out how to replace the serial monitor coding with console coding,
Serial and Console both derive from the same Stream class, so they have the same interface and work much the same way. Switching your sketch over is easy: first, you need to add #include <Console.h> at the beginning of your sketch. Then, change your Serial.begin() statement to Console.begin() with no arguments, and make sure it is s called after Bridge.begin() is called. Finally, change every occurrence of Serial in your sketch to Console. All of the print(), println() and other functions are the same and will not need any changes.

stgeorge

I figured!  I had this initial hunch that I needed to be working over Console due to wifi, but what had been throwing me off is that, on occasion, I'd see 'connected' in the serial monitor- but then it wouldn't actually communicate, so I knew something was wrong.

Anyway- I'll be working on a conversion to console for a bit and report back what I'm seeing/hearing from the mcu.  I'm really interested to learn why this runCurl loop isn't working.

I assume you don't need to call out any baud rate on either the bridge or the console, right?

Does it matter the order in which you list the 'include' libraries (?) - I'm guessing not.

Finally...since I've run across 'boolean' I'm curious if you can shed light on what that does and/or what the proper use is for it?  I've certainly heard of Boolean search nomenclature et al but haven't run across it in programming code until recently.

ShapeShifter

I assume you don't need to call out any baud rate on either the bridge or the console, right?
Correct.

Bridge.begin() can accept an optional baud rate, because it is actually a serial port connection to the Linux processor. They give you the option of changing that baud rate if you have a special need.

Console.begin() expects no parameters. There is no concept of a baud rate for a network connection. While a network connection does have a physical data signalling speed, that is a function of the physical hardware interface and not something that can be changed in software. (Or at least not by the Console class.)

Quote
Does it matter the order in which you list the 'include' libraries (?) - I'm guessing not.
Sometimes it matters, usually it doesn't. There may be a case where an include file needs to use information from another include file, and therefore must be included after the other one. But usually, that include file will just include the specific file it needs, eliminating the need to include them in a specific order. (Wow, talk about some convoluted logic, any chance you can follow that?)

In the case of these include files, it doesn't really matter. I like to include Bridge.h first, as it is the main include file of the Bridge library, and everything else depends on it. However, because everything else depends on it, it is automatically included by the other include files. So, if you happen to include Console.h first, it will include Bridge.h internally to it. Then, when you get to the point where you are including it in your sketch, the compiler will realize that it's already been included and not include it a second time.

But the short answer is no, it usually doesn't matter. In general, I tend to include files in alphabetical order: sometimes there is a long list of includes in a source file, and having them in order makes it easier to find a file in the list when reading the code.

Quote
Finally...since I've run across 'boolean' I'm curious if you can shed light on what that does and/or what the proper use is for it?
A boolean is usually another name for an unsigned char (byte.)

It represents a logical value: either true or false. The results of the comparison operators (==, >, <, <=, >=, etc) is a logical value. There are logical operators that take logical values and return logical results like and (&) or (|) exclusive-or (^) and not (!). There are statements that expect logical expressions, like if and while.

C++ uses the numeric value 0 to represent false, and any non-zero numeric value is considered true. The result of a comparison or logical operator is usually 1 when it wants to signal true.

A logical value can be stored in just about any integral numeric variable type, although a single byte value is usually used for efficiency. "boolean" is just another form of unsigned character value (just like "byte") that can be used to store any 8-bit value, but by using the type "boolean" you are giving the reader a hint that you intend to use it for true/false values. (Although the compiler really doesn't care, it treats "byte", "boolean", and "unsigned char" as the same thing: an unsigned 8-bit value.)

stgeorge

Thanks for that.

OK- so I've converted my little sketch to console and the first time around, it showed 'connected' in the serial monitor, but now I'm not often even seeing that.

I'm now wondering if I have my network setup correctly for this console communicating.  Because it worked this way for the consoleread example sketch, I'm again thinking that it is fine, but now maybe not. 

I read in the consoleread sketch intro that you either telnet to the board or port forward the board and open a serial monitor to connect and see print and other feedback.  I port forwarded the board's ip on my lan to 6571 and again, since it worked, I have left it that way, but what is odd to me is that port forwarding is really for outside the lan access to a device on the lan, so this doesn't really make a lot of sense to me because I'm trying to monitor this board's mcu from within my lan.  Is there a better way to set this up and/or to open or connect to the console?

Here's my code currently:

Code: [Select]

// set pin number:
const int buttonPin = 3;     // the number of the doorbell input
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

#include <Bridge.h>
#include <Process.h>
#include <Console.h>

void setup() {
   // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  Bridge.begin();
  Console.begin();
}

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
    runCurl();
    delay(750);
 
  } else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }
}

void runCurl() {
 Process p;           
 p.begin("/usr/bin/curl");
 p.addParameter("-d");
 p.addParameter("\"devid=vBECBF1F4A7D765\"");
 p.addParameter("http://api.pushingbox.com/pushingbox");
 p.run();
 while (p.available()>0)
 {
   char c = p.read();
   Console.print(c);
 }
}


The led light and button pressing etc all works fine, including the delay, but no serial monitor communication and definitely no success with the runCurl loop.

Go Up