aws / aws-iot-device-sdk-arduino-yun

SDK for connecting to AWS IoT from an Arduino Yún.
Apache License 2.0
163 stars 77 forks source link

Getting help and delay(10000) #58

Closed flycast closed 6 years ago

flycast commented 6 years ago

Two questions:

Is this the best place to get help with AWS/Arduino Yun and this SDK? I have posted a couple of times last week only to receive deafening silence.

I am connected and am seeing messages published now...yay!

I found that if I change the delay(1000) to delay(10000) in the following code:

void loop() {
  if(success_connect) {
    // Generate a new message in each loop and publish to "topic1"
    sprintf(msg, "new message %d", cnt);
    if((rc = myClient.publish("topic1", msg, strlen(msg), 1, false)) != 0) {
      Serial.println(F("Publish failed!"));
      Serial.println(rc);
    }

    // Get a chance to run a callback
    if((rc = myClient.yield()) != 0) {
      Serial.println("Yield failed!");
      Serial.println(rc);
    }

    // Done with the current loop
    sprintf_P(msg, PSTR("loop %d done"), cnt++);
    Serial.println(msg);

    delay(9925);
  }
}

I get to following errors:

AWS IoT SDK Version(dev) 2.2.0-

loop 0 done Publish failed! -1 Yield failed! -35 loop 1 done

Tweaking somewhat I have found that it stops working when the delay value is somewhere between 9925 and 10000. Reading the docs on delay I find the following:

While it is easy to create a blinking LED with the delay() function, and many sketches use short delays for such tasks as switch debouncing, the use of delay() in a sketch has significant drawbacks. No other reading of sensors, mathematical calculations, or pin manipulation can go on during the delay function, so in effect, it brings most other activity to a halt. For alternative approaches to controlling timing see the millis() function and the sketch sited below. More knowledgeable programmers usually avoid the use of delay() for timing of events longer than 10's of milliseconds unless the Arduino sketch is very simple.

What is happening here? Is the delay tying up the Yun and preventing communications through the bridge or something?

flycast commented 6 years ago

More information on this... Reading about adding the line after line 851: Serial.println(rw_buf); to this file https://github.com/aws/aws-iot-device-sdk-arduino-yun/blob/master/AWS-IoT-Arduino-Yun-Library/aws_iot_mqtt.cpp#L851

I get the following information in the serial monitor:

First, a good message:

P T

Z T

Y 0 0 new message 2 CALLBACK: new message 2

Y F: No messages.

The I wait a minute and the I get (the "Exe" is really missing from the first line):

eption in thread Thread-1 (most likely raised during interpr5 /bin/ash: p: not found /bin/ash: topic1: not found /bin/ash: new: not found /bin/ash: 1: not found /bin/ash: 0: not found Publish failed! -1 /bin/ash: 1: not found /bin/ash: z: not found Yield failed! -35

After that no matter how long I wait I get (notice the missing exception in thread1?:

/bin/ash: 5: not found /bin/ash: p: not found /bin/ash: topic1: not found /bin/ash: new: not found /bin/ash: 1: not found /bin/ash: 0: not found Publish failed! -1 /bin/ash: 1: not found /bin/ash: z: not found Yield failed! -35

Sorry for my lack of knowledge.

flycast commented 6 years ago

@liuszeng

Any chance I could get you to look at this? I'd really appreciate your help.

flycast commented 6 years ago

Wow...I feel like I am an old man walking down the road and talking to myself!

What I have discovered...

If the delay between each publish is less than about 9.5 seconds then you can connect once and publish to your hearts content. It does not seem to matter what you set the keep alive at in the connect command.

If my next publish is going to be longer than about 9.5 seconds from my last publish then I have to disconnect, do a new setup, an new config and then a new connect.

Serial.println("Attempting to connect...");
rc = myClient.setup(AWS_IOT_CLIENT_ID);
rc = myClient.config(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, AWS_IOT_ROOT_CA_PATH, AWS_IOT_PRIVATE_KEY_PATH, AWS_IOT_CERTIFICATE_PATH);
if((rc = myClient.connect()) == 0) {
          //Do stuff with the connection...
          myClient.disconnect();
}

If I do not I get the following error...

Attempting to connect...

Exception in thread Thread-4 (most likely raised during interp Connection failed!

After that error every time it connects I get these errors:

Attempting to connect... /bin/ash: 2: not found /bin/ash: c: not found /bin/ash: 60: not found Connection failed!

What is happening here?

jimisataws commented 6 years ago

@flycast, apologize for the delayed response. @liuszeng (expert on Arduino Yun) is not available right now. Our team will investigate this as soon as possible and get back to you.

Thank you for using AWS IoT.

hedeshianaws commented 6 years ago

@flycast The python-based command server which gets spawned on the AR9331 expects traffic over the serial link periodically. You need to be calling myClient.yield() on the MCU frequently otherwise the serial link between the ATmega32u4 and the AR9331 will go dormant and the back-end process will quit (it thinks the ATmega has crashed and will relinquish control of the serial line). If you want to reduce the frequency of sending messages, you can take a modulo of the loop count. The sample below will only publish every 10 seconds:

void loop() {
  if(success_connect) {
    if (!(cnt % 10)) {
      // Generate a new message in each loop and publish to "topic1"
      sprintf(msg, "new message %d", cnt/10);
      if((rc = myClient.publish("topic1", msg, strlen(msg), 1, false)) != 0) {
        Serial.println(F("Publish failed!"));
        Serial.println(rc);
      }
    }

    // Get a chance to run a callback
    if((rc = myClient.yield()) != 0) {
      Serial.println("Yield failed!");
      Serial.println(rc);
    }

    // Done with the current loop
    sprintf_P(msg, PSTR("loop %d done"), cnt++);
    Serial.println(msg);

    delay(1000);
  }
}
flycast commented 6 years ago

Thank you for the response. So it is a "undocumented enhancement" between the processor and the serial communications in the Yun. I need to basically "ping" some traffic from the processor and the serial communications.

It's not that I want to send a message every 10 seconds in this case. I want to loop and wait for a switch to be closed. The switch may get closed 15 times in a minute and then not get closed again for a week. What I am really reaching for is a way to handle the sporadic sending of MQTT messages.

Alternate question...Is there a better hardware platform for an in machine IoT processor that can look at one to multiple switches or voltage inputs upon which to base my project on? I will just be starting with less than 10 in a small area of the plant. That number may grow considerably if this is successful.

hedeshianaws commented 6 years ago

Thank you for the response. So it is a "undocumented enhancement" between the processor and the serial communications in the Yun. I need to basically "ping" some traffic from the processor and the serial communications.

I wouldn't call it an "undocumented enhancement". Remember that the Yun has 2 processors: the ATmega MCU or I/O controller for which you write your "Arduino sketch", and a connectivity processor which runs Linux. The MCU (ATmega32u4) and the connectivity processor (AR9331) share a serial link. If that link goes dormant, the part of the SDK which runs on the AR9331 will timeout and exit. You just need to keep calling myClient.yield() from the MCU often enough to keep the AR9331 portion of the SDK from quitting.

It's not that I want to send a message every 10 seconds in this case. I want to loop and wait for a switch to be closed. The switch may get closed 15 times in a minute and then not get closed again for a week.

This would be a simple change. You still fire the loop every second.

void loop() {
  if(success_connect) {
    if (switch_is_closed()) {
      // Generate a new message in each loop and publish to "topic1"
      sprintf(msg, "new message %d", cnt/10);
      if((rc = myClient.publish("topic1", msg, strlen(msg), 1, false)) != 0) {
        Serial.println(F("Publish failed!"));
        Serial.println(rc);
      }
    }

    // Get a chance to run a callback
    if((rc = myClient.yield()) != 0) {
      Serial.println("Yield failed!");
      Serial.println(rc);
    }

    // Done with the current loop
    sprintf_P(msg, PSTR("loop %d done"), cnt++);
    Serial.println(msg);

    delay(1000);
  }
}

Alternate question...Is there a better hardware platform for an in machine IoT processor that can look at one to multiple switches or voltage inputs upon which to base my project on? I will just be starting with less than 10 in a small area of the plant. That number may grow considerably if this is successful.

What is your criteria for better? There are a number of off-the-shelf components which can be used depending on your volume, reliability requirements, cost, engineering resources. The Yun is a good place to prototype, but I'm not sure I'd want to take it into production with the SDK as-is. At a minimum, I think you'll want to use the Python IoT SDK directly on the AR9331 and write your own arbiter for the inter-processor serial link.

ghost commented 6 years ago

Hi hedeshianaws,

I bumped into the similar problem, which I explained in a new thread, but having read your explanation, everything felt into place, and the sketch works. many thanks for the explanation.

Regards, Dennis

hedeshianaws commented 6 years ago

Closing due to inactivity. Please feel free to open an new issue if you have any additional questions.