diff --git a/content/arduino-cloud/01.getting-started/02.technical-reference/iot-cloud-tech-ref.md b/content/arduino-cloud/01.getting-started/02.technical-reference/iot-cloud-tech-ref.md index f07d91a0f7..20578b038a 100644 --- a/content/arduino-cloud/01.getting-started/02.technical-reference/iot-cloud-tech-ref.md +++ b/content/arduino-cloud/01.getting-started/02.technical-reference/iot-cloud-tech-ref.md @@ -308,11 +308,29 @@ One or more **Things** can be added to a **Dashboard**, with all or some of thei ![Create widgets from a Thing](./images/create-widget-from-thing.png) -***You can read more about [Dashboards & Widgets]().*** +***You can read more about [Dashboards & Widgets](/arduino-cloud/getting-started/dashboard-widgets).*** ## Recommended Code Practices -### Avoid blocking commands within the loop() +This section highlights some important aspects of writing code with regard to the implementations in the [ArduinoIoTCloud](https://github.com/arduino-libraries/ArduinoIoTCloud). + +### Watchdog Timer (WDT) + +All IoT Cloud sketches use a **Watchdog Timer (WDT)** by default. The WDT can be used to automatically recover from hardware faults or unrecoverable software errors. + +A WDT is essentially a countdown timer, whereas it starts counting from a set value, and upon reaching zero, it resets the board. To prevent it from reaching zero, we continuously call it from the `loop()`, using the `ArduinoCloud.update()` function. + +This is why, it is very important to not use any long blocking code in your sketch. For example, using a long `delay()` inside the `loop()` is **strongly discouraged**, as the WDT can reach zero and reset the board. + +The WDT can however be disabled inside of the `setup()` function, by adding the `false` parameter: + +```arduino +ArduinoCloud.begin(ArduinoIoTPreferredConnection, false). +``` + +***You can view the source code of this implementation [here](https://github.com/arduino-libraries/ArduinoIoTCloud/tree/master/src/utility/watchdog).*** + +### Alternatives to Delays The `loop()` function includes the `ArduinoCloud.update();` call, which sends data to the cloud and receives updates. In order to get the best responsiveness in your cloud-connected projects, the `loop()` function should run as fast as possible. This means that no blocking commands should be used inside, and you should prefer a non-blocking programming approach whenever possible. @@ -320,30 +338,59 @@ A common **blocking pattern** is the use of the `delay()` function which stops t Let's see how to blink a LED. The traditional way involves the `delay()` function: - void loop() { - ArduinoCloud.update(); - - digitalWrite(LED_BUILTIN, HIGH); - delay(1000); - digitalWrite(LED_BUILTIN, LOW); - delay(1000); - } +```arduino +void loop() { + ArduinoCloud.update(); + + digitalWrite(LED_BUILTIN, HIGH); + delay(1000); + digitalWrite(LED_BUILTIN, LOW); + delay(1000); +} +``` This works, but it will cause a delay of at least two seconds between one execution of `ArduinoCloud.update()` and the next one, thus causing bad performance of the cloud communication. This can be rewritten in a non-blocking way as follows: - void loop() { - ArduinoCloud.update(); - - digitalWrite(LED_PIN, (millis() % 2000) < 1000); - } +```arduino +void loop() { + ArduinoCloud.update(); + + digitalWrite(LED_PIN, (millis() % 2000) < 1000); +} +``` How does this work? It gets the current execution time provided by `millis()` and divides it by 2 seconds. If the remainder is smaller than one second it will turn the LED on, and if it's greater it will turn the LED off. For a more complex and commented example, you can have a look at the [BlinkWithoutDelay example](/built-in-examples/digital/BlinkWithoutDelay). -### Avoid waiting for Serial Monitor to initialize connection +### I2C Usage + +Components connected via I²C (including the sensors onboard the [MKR IoT Carrier](https://store.arduino.cc/products/arduino-mkr-iot-carrier)) uses the same bus as the **ECCX08** cryptochip. As the crypto chip is an essential part of establishing a connection to the IoT Cloud (it contains the credentials), it is important that other I²C peripherals are initialized after the connection has been made. + +For example, if you are initializing a library such as [Arduino_MKRENV](https://www.arduino.cc/reference/en/libraries/arduino_mkrenv), your `setup()` should be implemented as: + +```arduino +void setup() { + Serial.begin(9600); + delay(1500); + + initProperties(); + + ArduinoCloud.begin(ArduinoIoTPreferredConnection); + setDebugMessageLevel(2); + ArduinoCloud.printDebugInfo(); + + //initializing the Arduino_MKRENV library + if (!ENV.begin()) { + Serial.println("Failed to initialize MKR ENV shield!"); + while (1); + } +``` + + +### Avoid Blocking Serial Communication `while(!Serial) {}` loops endlessly until the Serial Monitor is opened. This is a useful practice in cases where you want to see all debug output from the start of the sketch execution. However, when building IoT systems using **`while(!Serial){}` can hinder our project from running autonomously**, stopping the board from connecting to the network and IoT Cloud before manually opening the Serial Monitor. Therefore, it is recommended to consider removing the `while(!Serial){}` loop if it's not necessary.