Arduino-Yun Wifi - Internet Commands?

That's a good idea- you mean from a bash prompt on root? When I open a terminal and SSH into the Yun, I login as root and get to a prompt...do you then just start typing each line of that runCurl code?

How do you use the v and/or trace? Do you mean, try putting them in the sketch somehow?

stgeorge:
I login as root and get to a prompt...do you then just start typing each line of that runCurl code?

Yes, that's exactly what I mean. But just to be accurate (in case you go searching the web for help) it's not a bash prompt, it's ash. It's mostly the same, but there are some differences that could catch you.

How do you use the v and/or trace? Do you mean, try putting them in the sketch somehow?

I would use them when you're experimenting on the command line. Just add the options to whatever command you're testing. For example, your basic curl command is:

curl -d "devid=v0123456789ABCDE" http://api.pushingbox.com/pushingbox

To add the verbose command:

curl -v -d "devid=v0123456789ABCDE" http://api.pushingbox.com/pushingbox

To add the trace command:

curl --trace -d "devid=v0123456789ABCDE" http://api.pushingbox.com/pushingbox

Each of those are the command as you would type it on the command line.

Thanks- before reading your last comment, I tried that line (without the -v or --trace) and am getting a bigger problem...that is, I'm getting:

curl: (6) Couldn't resolve the host 'api.pushingbox.com'

So on a hunch, I went into my admin controls on the Yun and looked at my wifi setup, thinking that since I had locked down the IP address on my LAN for this Arduino, I may have failed to properly set the DNS address. I had indeed left it blank thinking that it would then default to the router's DNS settings, so I added the router's address in that blank (aka the gateway address).

Retried it via command line and I'd love to tell you that it worked, but alas, same problem.... ugh!

Any thoughts?

stgeorge:
Any thoughts?

To get you past this current stumbling block, I would try substituting the IP address 213.186.33.19 in place of api.pushingbox.com. (I got that address just now by running "nslookup api.pushingbox.com" on my computer.) You're better off using the name rather than the numeric address, in case the address ever changes in the future.

In the long run, you will have to sort out your DNS issues, but this should work as temporary work-around.

Thanks- tried that too- now I'm getting lots of fun gobbledy gook! I think I need to have a chat with the pushingbox folks....

stgeorge:
I think I need to have a chat with the pushingbox folks....

Good plan. This is the place for support to figure out how to call curl on the Yun. But they are the place for help on what parameters to use when calling curl.

Once you work with them and figure out a curl command that works when typed on the Yun's command line, we can make it work in the sketch.

Breakthrough!

Ok- firstly, I have sent a note to the French Pushingbox folks, but they must be on vacation or something because no response yet.

But- then I traded a few emails with a very helpful technician with Dragino Yun over in China and it seems I had two network problems. First, I mistakenly thought the 'broadcast' address was the address that would be broadcast out over the LAN (similar to broadcast ssid) but that is obviously wrong, so we got that set correctly. Second, which was probably the real issue, the Admin GUI imbedded in the Yun where I set my fixed IP address on the LAN has a field entitled, "Use Custom DNS Server(s): __________" and I had left that blank because my experience with other networked devices has been that, in the absence of a customized dns setting, the device will look to the router's dns settings. This goes back to the language / cultural misunderstandings that I discussed earlier. Anyway, I set the 'custom' dns to my router's address and boom, it works great!

I executed the curl command from an ash prompt and pow- straight through successfully!

Now that I have it communicating properly with the outside world, I need to go back and experiment with my various iterations of this sketch...

Congratulations! Great work chewing your way through the issues.

This issue / misunderstanding is causing a lot of people to have the same / similar troubles. If you google Arduino couldn't resolve... many of them pop up- most old, but I'm wondering if there's not a way to somehow post this as a common misunderstanding with the Yun's GUI...

So I'm now trying to make this as simple as possible....

As we have confirmed- when I SSH into the Dragino Yun on top of an Arduino Leonardo board, and type the following at a command prompt:

curl -d "devid=vBECBF1F4A7D765" http://api.pushingbox.com/pushingbox

...it works like a champ.

Now, attempting to merge that curl command with a fairly typical (and working) button check, I have the following sketch:

// 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();
}

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();
} 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();
}

And again, it compiles fine, and loads fine, and the button works properly (i.e. the LED on the Arduino lights up when the button is pressed etc), but the call (listed at top) is not effectively executed after the LED lights up.

Do you see anything that would otherwise cause it to not work correctly here? Thanks

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

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:

 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.

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

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

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

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.

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.

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.

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

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.

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);
}
}

This doesn't look right:

  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.

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.

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

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

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.

stgeorge:
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:

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.

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

Read this...