diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml
index 85f81c4d..bdbae3ec 100644
--- a/.github/workflows/workflow.yaml
+++ b/.github/workflows/workflow.yaml
@@ -51,28 +51,6 @@ jobs:
--content-type 'text/markdown' \
--cache-control max-age=0,no-cache,no-store,must-revalidate
- - name: Datasheet generation
- run: |
- cd scripts/datasheet-generator
- npm install
- cd ../../
- ./generate-datasheets
-
- - name: S3 sync (Datasheet PDFs)
- run: |
- aws s3 sync \
- build/datasheets \
- s3://${{ secrets.S3_BUCKET_NAME }}/content/datasheets/ \
- --no-progress \
- --acl public-read \
- --follow-symlinks \
- --delete \
- --metadata-directive REPLACE \
- --exclude '*' \
- --include '*.pdf' \
- --content-type 'application/pdf' \
- --cache-control max-age=0,no-cache,no-store,must-revalidate
-
- name: Invalidate CloudFront distribution
run: |
aws cloudfront create-invalidation \
diff --git a/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_3wirevalve_cover.svg b/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_3wirevalve_cover.svg
new file mode 100644
index 00000000..d93642d2
--- /dev/null
+++ b/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_3wirevalve_cover.svg
@@ -0,0 +1,672 @@
+
diff --git a/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_connect_power_source.svg b/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_connect_power_source.svg
new file mode 100644
index 00000000..050eea1a
--- /dev/null
+++ b/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_connect_power_source.svg
@@ -0,0 +1,491 @@
+
diff --git a/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_connect_valve.svg b/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_connect_valve.svg
new file mode 100644
index 00000000..389960bf
--- /dev/null
+++ b/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_connect_valve.svg
@@ -0,0 +1,854 @@
+
diff --git a/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_valve_wires.svg b/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_valve_wires.svg
new file mode 100644
index 00000000..968a64cb
--- /dev/null
+++ b/content/tutorials/portenta-h7/ec-ard-3wirevalve/assets/ec_ard_valve_wires.svg
@@ -0,0 +1,25 @@
+
diff --git a/content/tutorials/portenta-h7/ec-ard-3wirevalve/content.md b/content/tutorials/portenta-h7/ec-ard-3wirevalve/content.md
new file mode 100644
index 00000000..0a96ac22
--- /dev/null
+++ b/content/tutorials/portenta-h7/ec-ard-3wirevalve/content.md
@@ -0,0 +1,160 @@
+---
+title: Connecting and Controlling a Motorized Ball Valve
+coverImage: assets/ec_ard_3wirevalve_cover.svg
+tags: [Edge Control, Motorised Valve, Irrigation]
+description: This tutorial will give you an overview of the core features of the board, setup the development environment and introduce the APIs required to program the board.
+---
+
+# Connecting and Controlling a Motorized Ball Valve
+
+## Overview
+
+A ball valve is a form of quarter-turn [valve](https://en.wikipedia.org/wiki/Valve) which uses a hollow, perforated and pivoting ball to control flow of liquids and gasses through it. This tutorial will guide you through connecting the board to a 3 Wire-Valve and writing a sketch that controls the basic operations such as the opening and closing of the valves.
+
+***Tip : If this is for your first Edge Control project, we recommend you to take a look at the [Getting Started Tutorial](https://www.arduino.cc/pro/tutorials/portenta-h7/ec-ard-gs) to setup the development environment before you proceed.***
+
+### You Will Learn
+
+- How to connect a motorized valve to the Edge Control board
+- How to control the valve through basic commands provided by the `Arduino_EdgeControl` library
+- How to power the board with an external power supply
+
+### Required Hardware and Software
+
+- 1 x [Arduino Edge control board](https://store.arduino.cc/edge-control)
+- 1 x [US Solid Motorised Ball Valve (9 - 24 V)](https://ussolid.com/u-s-solid-motorized-ball-valve-1-2-brass-electrical-ball-valve-with-full-port-9-24-v-ac-dc-3-wire-setup.html) (or compatible)
+- External power source: 12V battery (LiPo / SLA) or power supply
+- 1 x Micro USB cable
+- Arduino IDE 1.8.10+
+- 2 x Phoenix connectors 1844646
+- 2 x Jumper cables
+
+## Instructions
+
+### 1. Connecting the Valves
+
+The motorized valve comes with three wires primarily marked as blue, yellow and red. The red and blue cables are for the positive and negative signals and the yellow is for the ground.
+
+
+
+You need to ensure that the Phoenix connectors are in place before plugging in the wires to the respective pins. If you havent link
+
+Connect the red and the blue wire to any of the 8 pairs of `LATCHING OUT` pins. In this example we will use `1N` and `1P` of your Edge Control board. Latches allow you to store the state of the pins based on the previous output. As the valve doesn't come with internal drivers to store the state of the motor, we will use the `Latching_out` pins (instead of `Latching_out_cmd`) that are the ones that include drivers on the Edge Control.
+
+
+
+Connect the yellow wire to the nearby `GND` pin. Ensure that the wires are fastened securely and tightly to the Phoenix connectors so that they make contact with the pins.
+
+### 2. Opening And Closing the Valves
+
+Open a new sketch file on the Arduino IDE and name it `ValveControl.ino`. Add the header file `Arduino_EdgeControl.h` to your sketch
+
+```cpp
+#include
+```
+
+Inside `void setup()` , after enabeling the serial communication, run the initialization routine `EdgeControl.begin()` . This routine is in charge of enabling the default power areas of the board. Then use `Latching.begin()` to configure the expander pins as outputs.
+
+```cpp
+void setup()
+{
+ Serial.begin(9600);
+ while(!Serial);
+
+ delay(1000);
+
+ Serial.println("3-Wire Valve Demo");
+
+ EdgeControl.begin();
+ Latching.begin();
+
+ Serial.println("Starting");
+}
+
+```
+
+Inside the `loop()`you will add the instructions to open and close the valve. `Latching.channelDirection()` is used to control the signal to a particular pin using the parameter `LATCHING_OUT_1` and its direction using the parameters, `POSITIVE` or `NEGATIVE`. Hence, if you want the valve to open you will use the instruction,
+
+```cpp
+Latching.channelDirection(LATCHING_OUT_1, POSITIVE)
+```
+
+and to close the valve, you need to send a signal in the opposite direction using the command,
+
+```cpp
+Latching.channelDirection(LATCHING_OUT_1, NEGATIVE)
+```
+
+As it takes a few seconds for the valve to fully open or close, you need to maintain the signal for a set amount of time. Using the command, `Latching.strobe(4500)` you can adjust the duration (milliseconds) of signal passing through a particular pin.
+
+```cpp
+void loop()
+{
+ Serial.println("Closing");
+ Latching.channelDirection(LATCHING_OUT_1, POSITIVE);
+ Latching.strobe(4500);
+ delay(2500);
+
+ Serial.println("Opening");
+ Latching.channelDirection(LATCHING_OUT_1, NEGATIVE);
+ Latching.strobe(4500);
+ delay(2500);
+}
+```
+
+### 3. Connecting To A Power Source
+
+The valves require a power supply of 9 - 12 V and you can either use a regular power supply or a 3 cell LiPo battery to provide the required voltage. Power sources can be connected to the onboard relay ports of the edge control board. Connect two jumper wires to the **GND** and **B** pins of the **Relay ports**
+
+
+
+Connect the jumper from the **B** pin to the positive terminal of the Battery and the jumper from the **GND** pin to the negative terminal of the battery
+
+### 4. Uploading the Sketch
+
+Connect the board to your computer, upload the `ValveControl.ino` sketch and open the **Serial Monitor**. If all the connections are done right, the valve opens and closes and you should be able to see the status as `Open` or `Close` on the serial monitor
+
+## Conclusion
+
+In this tutorial you learned how a 3 wire valve works and the basic operations that the Edge Control board uses to control the valves. With this knowledge you can build irrigation systems which periodically control the valves which can be installed in your fields.
+
+### Complete Sketch
+
+```cpp
+#include
+
+void setup()
+{
+ Serial.begin(9600);
+ while(!Serial);
+
+ delay(1000);
+
+ Serial.println("3-Wire Valve Demo");
+
+ EdgeControl.begin();
+ Latching.begin();
+
+ Serial.println("Starting");
+}
+
+void loop()
+{
+ Serial.println("Closing");
+ Latching.channelDirection(LATCHING_OUT_1, POSITIVE);
+ Latching.strobe(4500);
+ delay(2500);
+
+ Serial.println("Opening");
+ Latching.channelDirection(LATCHING_OUT_1, NEGATIVE);
+ Latching.strobe(4500);
+ delay(2500);
+}
+
+```
+
+**Authors:** Ernesto E. Lopez, Lenard George Swamy
+
+**Reviewed by:** Ernesto E. Lopez [2021-03-18]
+
+**Last revision:** Lenard George Swamy [2021-04-06]
diff --git a/content/tutorials/portenta-h7/ec-ard-gs/content.md b/content/tutorials/portenta-h7/ec-ard-gs/content.md
index 85a2a51c..8b2e0ac5 100644
--- a/content/tutorials/portenta-h7/ec-ard-gs/content.md
+++ b/content/tutorials/portenta-h7/ec-ard-gs/content.md
@@ -20,13 +20,13 @@ The Edge Control board is a versatile tool that allows agriculturalists to devel
- Arduino Edge Control ()
- Micro USB cable
- Arduino IDE 1.8.10+
-- External power source : a 12V LiPo/SLA battery or power supply
+- External power source : a 12V SLA battery or 12V power supply
- 1x Phoenix connector
- 2x Jumper wires
## Instructions
-In this getting started tutorial you will set up the Edge Control board and blink an LED. You will first learn to install the core from the Boards Manager. You will write a simple blink sketch using some fundamental APIs provided by the Arduino Edge Control Library. You will need to connect your board to an external power source and therefore have a LiPo battery or a power source with you when running the sketch.
+In this getting started tutorial you will set up the Edge Control board and blink an LED. You will first learn to install the core from the Boards Manager. You will write a simple blink sketch using some fundamental APIs provided by the Arduino Edge Control Library. You will need to connect your board to an external power source and therefore have a SLA battery or a power source with you when running the sketch.
### 1. Get to Know the Board
@@ -81,7 +81,7 @@ The board is designed to be very low power and for this reason some the electron

-The Edge Control board uses an I/O expander in order to increase the number of digital control signals. If we want to blink the on-board LED we would need to enable the power of the I/O expander to which the LED is connected to and also enable the power to the 5V DCDC converter. 5V power line is powered by the **battery source** for which you can either use a power supply or a 3 cell LiPo battery to provide the required voltage.
+The Edge Control board uses an I/O expander in order to increase the number of digital control signals. If we want to blink the on-board LED we would need to enable the power of the I/O expander to which the LED is connected to and also enable the power to the 5V DCDC converter. 5V power line is powered by the **battery source** for which you can either use a power supply or a SLA battery to provide the required voltage.
The `Power` class provides API access to enable the different voltages on the board. In this tutorial we need to enable the 3.3V and 5V power lines using the `enable3V3()` and `enable5V()` functions.
@@ -169,5 +169,5 @@ void loop() {
We are developing new tutorials on how to connect valves, LCDs, watermark sensors and use many other functionalities of the board. In the mean time you can explore the Arduino Edge Control library to develop your own application.
**Authors:** Lenard George
-**Reviewed by:** Ernesto Lopez [21.04.2021]
-**Last revision:** Sebastian Romero [22.04.2020]
\ No newline at end of file
+**Reviewed by:** Ernesto Lopez [2021-04-21]
+**Last revision:** Sebastian Romero [2020-04-22]
\ No newline at end of file
diff --git a/content/tutorials/portenta-h7/metadata.json b/content/tutorials/portenta-h7/metadata.json
index 95974e25..81f93271 100644
--- a/content/tutorials/portenta-h7/metadata.json
+++ b/content/tutorials/portenta-h7/metadata.json
@@ -19,6 +19,8 @@
"por-ard-kvs",
"vs-ard-ttn",
"por-ard-lvgl",
+ "vs-openmv-ttn",
+ "por-openmv-gs",
"vs-openmv-ml",
"ec-ard-gs"
]
diff --git a/content/tutorials/portenta-h7/por-ard-gs/content.md b/content/tutorials/portenta-h7/por-ard-gs/content.md
index 5b471522..1ead36b7 100644
--- a/content/tutorials/portenta-h7/por-ard-gs/content.md
+++ b/content/tutorials/portenta-h7/por-ard-gs/content.md
@@ -58,9 +58,10 @@ In this step you will check if Windows is able to detect the Portenta H7. To do

### 4. Uploading the Classic Blink Sketch
-Let's program the Portenta with the classic blink example to check if the connection to the board works:
+Let's program the Portenta with the classic blink example to check if the connection to the board works. There are two ways to do that:
-- In the classic Arduino IDE open the blink example by clicking the menu entry File->Examples->01.Basics->Blink.
+- In the classic Arduino IDE open the blink example by clicking the menu entry File->Examples->01.Basics->Blink. You need to swap LOW and HIGH pin values as the built-in LED on Portenta is turned on by pulling it LOW.
+- By downloading the 'Arduino_Pro_Tutorials' library and opening the pre-made sketch under File->Examples->Arduino_Pro_Tutorials->Setting Up Portenta H7 For Arduino->Blink
- In the Arduino Pro IDE Copy and paste the following code into a new sketch in your IDE.
```cpp
diff --git a/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_board_connected.png b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_board_connected.png
new file mode 100644
index 00000000..5b55ac9c
Binary files /dev/null and b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_board_connected.png differ
diff --git a/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_click_connect.png b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_click_connect.png
new file mode 100644
index 00000000..3aba99a9
Binary files /dev/null and b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_click_connect.png differ
diff --git a/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_firmware_updater.png b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_firmware_updater.png
new file mode 100644
index 00000000..0c388077
Binary files /dev/null and b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_firmware_updater.png differ
diff --git a/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_gs_cover.svg b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_gs_cover.svg
new file mode 100644
index 00000000..1904a263
--- /dev/null
+++ b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_gs_cover.svg
@@ -0,0 +1,883 @@
+
diff --git a/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_open_ide.png b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_open_ide.png
new file mode 100644
index 00000000..8bbb9a34
Binary files /dev/null and b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_open_ide.png differ
diff --git a/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_reset_firmware.png b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_reset_firmware.png
new file mode 100644
index 00000000..8038d067
Binary files /dev/null and b/content/tutorials/portenta-h7/por-openmv-gs/assets/por_openmv_reset_firmware.png differ
diff --git a/content/tutorials/portenta-h7/por-openmv-gs/content.md b/content/tutorials/portenta-h7/por-openmv-gs/content.md
new file mode 100644
index 00000000..018c9715
--- /dev/null
+++ b/content/tutorials/portenta-h7/por-openmv-gs/content.md
@@ -0,0 +1,160 @@
+---
+title: Getting Started with OpenMV and MicroPython
+coverImage: assets/por_openmv_gs_cover.svg
+tags: [Getting Started, OpenMV, Setup, Blink, MicroPython]
+description: This tutorial teaches you how to set up the board, how to use the OpenMV IDE and how to run a MicroPython blink example with OpenMV.
+---
+
+# Getting Started with OpenMV and MicroPython
+## Overview
+The OpenMV IDE is meant to provide an Arduino like experience for simple machine vision tasks using a camera sensor. In this tutorial, you will learn about some of the basic features of the OpenMV IDE and how to create a simple MicroPython script.
+
+### You Will Learn
+- The basic features of the OpenMV IDE
+- How to create a simple MicroPython script
+- How to use the OpenMV IDE to run MicroPython on Portenta H7
+
+
+### Required Hardware and Software
+- Portenta H7 board ()
+- USB-C cable (either USB-A to USB-C or USB-C to USB-C)
+- Portenta Bootloader Version 20+
+- OpenMV IDE 2.6.4+
+
+## Instructions
+
+Using the OpenMV IDE you can run [MicroPython](http://docs.MicroPython.org/en/latest/) scripts on the Portenta H7 board. MicroPython provides a lot of classes and modules that make it easy to quickly explore the features of the Portenta H7. In this tutorial you will first download the OpenMV IDE and set up the development environment. [Here](https://openmv.io/) you can read more about the OpenMV IDE. OpenMV comes with its own firmware that is built on MicroPython. You will then learn to write a simple script that will blink the on-board RGB LED using some basic MicroPython commands.
+
+### 1. Downloading the OpenMV IDE
+
+Before you can start programming OpenMV scripts for the Portenta you need to download and install the OpenMV IDE.
+
+***IMPORTANT: Before you connect the Portenta to the OpenMV IDE make sure you update the bootloader as explained in the "Flashing the OpenMV Firmware" section!***
+
+Open the [OpenMV download](https://openmv.io/pages/download) page in your browser, download the version that you need for your operating system and follow the instructions of the installer.
+
+### 2. Flashing the OpenMV Firmware
+
+Connect the Portenta to your computer via the USB-C cable if you haven't done so yet. Make sure you first update the bootloader to the latest version using the **PortentaH7_updateBootloader** sketch in the examples menu in the Arduino IDE.
+
+Instructions on how to update the bootloader can be found in the ["Updating the Portenta Bootloader" tutorial](https://www.arduino.cc/pro/tutorials/portenta-h7/por-ard-bl).
+
+After updating the bootloader put the Portenta in bootloader mode by double-pressing the reset button on the board. The built-in green LED will start fading in and out. Now open the OpenMV IDE.
+
+
+
+Click on the "connect" symbol at the bottom of the left toolbar.
+
+
+
+A pop-up will ask you how you would like to proceed. Select "Reset Firmware to Release Version". This will install the latest OpenMV firmware on the Portenta H7. You can leave the option of erasing the internal file system unselected and click "OK".
+
+
+
+Portenta H7's green LED will start flashing while the OpenMV firmware is being uploaded to the board. A terminal window will open which shows you the flashing progress. Wait until the green LED stops flashing and fading. You will see a message saying "DFU firmware update complete!" when the process is done.
+
+
+
+***Installing the OpenMV firmware will overwrite any existing sketches in the internal flash of Portenta H7. Also the M7 port won't be exposed in the Arduino IDE anymore. To re-flash the M7 with an Arduino firmware you need to put the board into bootloader mode. To do so double press the reset button on the Portenta H7 board. The built-in green LED will start fading in and out. In bootloader mode you will see the Portenta M7 port again in the Arduino IDE.***
+
+The board will start flashing its blue LED when it's ready to be connected. After confirming the completion dialog the Portenta H7 should already be connected to the OpenMV IDE, otherwise click the "connect" button (plug symbol) once again.
+
+
+
+### 3. Preparing the Script
+
+Create a new script by clicking the "New File" button in the toolbar on the left side. Import the required module `pyb`:
+
+```py
+import pyb # Import module for board related functions
+```
+
+A module in Python is a confined bundle of functionality. By importing it into the script it gets made available. For this example we only need `pyb`, which is a module that contains board related functionality such as PIN handling. You can read more about its functions [here](https://docs.micropython.org/en/latest/library/pyb.html).
+
+Now we can create the variables that will control our built-in RGB LED. With `pyb` we can easily control each colour.
+
+```py
+redLED = pyb.LED(1) # built-in red LED
+greenLED = pyb.LED(2) # built-in green LED
+blueLED = pyb.LED(3) # built-in blue LED
+```
+
+Now we can easily distinguish between which color we control in the script.
+
+### 4. Creating the Main Loop in the Script
+
+Putting our code inside a while loop will make the code run continuously. In the loop we turn on an LED with `on`, then we use the `delay` function to create a delay. This function will wait with execution of the next instruction in the script. The duration of the delay can be controlled by changing the value inside the parentheses. The number defines how many milliseconds the board will wait. After the specified time has passed, we turn off the LED with the `off` function. We repeat that for each colour.
+
+```py
+while True:
+ # Turns on the red LED
+ redLED.on()
+ # Makes the script wait for 1 second (1000 miliseconds)
+ pyb.delay(1000)
+ # Turns off the red LED
+ redLED.off()
+ pyb.delay(1000)
+ greenLED.on()
+ pyb.delay(1000)
+ greenLED.off()
+ pyb.delay(1000)
+ blueLED.on()
+ pyb.delay(1000)
+ blueLED.off()
+ pyb.delay(1000)
+```
+
+### 5. Uploading the Script
+
+Here you can see the complete blink script:
+
+```py
+import pyb # Import module for board related functions
+
+redLED = pyb.LED(1) # built-in red LED
+greenLED = pyb.LED(2) # built-in green LED
+blueLED = pyb.LED(3) # built-in blue LED
+
+while True:
+
+ # Turns on the red LED
+ redLED.on()
+ # Makes the script wait for 1 second (1000 miliseconds)
+ pyb.delay(1000)
+ # Turns off the red LED
+ redLED.off()
+ pyb.delay(1000)
+ greenLED.on()
+ pyb.delay(1000)
+ greenLED.off()
+ pyb.delay(1000)
+ blueLED.on()
+ pyb.delay(1000)
+ blueLED.off()
+ pyb.delay(1000)
+```
+
+Connect your board to the OpenMV IDE and upload the above script by pressing the play button in the lower left corner.
+
+
+
+Now the built-in LED on your Portenta board should be blinking red, green and then blue repeatedly.
+
+## Conclusion
+In this tutorial you learned how to use the OpenMV IDE with your Portenta board. You also learned how to control the Portenta H7's RGB LED with MicroPython functions and to upload the script to your board using the OpenMV IDE.
+
+### Next Steps
+- Experiment with MicroPythons capabilities. If you want some examples of what to do, take a look at the examples included in the OpenMV IDE. Go to: **File>Examples>Arduino>Portenta H7** in the OpenMV IDE.
+- Take a look at our other Portenta H7 tutorials which showcase its many uses. You can find them [here](https://www.arduino.cc/pro/tutorials/portenta-h7)
+
+## Troubleshooting
+### OpenMV Firmware Flashing Issues
+- If the upload of the OpenMV firmware fails during the download, put the board back in bootloader mode and try again. Repeat until the firmware gets successfully uploaded.
+- If the OpenMV IDE still can't connect after flashing the firmware, try uploading the latest firmware using the "Load Specific Firmware File" option. You can find the latest firmware in the [OpenMV Github repository](https://github.com/openmv/openmv/releases). Look for a file named **firmware.bin** in the PORTENTA folder.
+- If you experience issues putting the board in bootloader mode, make sure you first update the bootloader to the latest version using the **PortentaH7_updateBootloader** sketch from the examples menu in the Arduino IDE.
+- If you see a "OSError: Reset Failed" message, reset the board by pressing the reset button. Wait until you see the blue LED flashing, connect the board to the OpenMV IDE and try running the script again.
+- In bootloader versions 17 and older there was a bug that could put the Portenta into a boot loop when the transmission aborted while flashing a large firmware file. This was fixed in the bootloader version 18.
+
+**Authors:** Sebastian Romero, Benjamin Dannegård
+**Reviewed by:** Lenard George [2021-04-12]
+**Last revision:** Sebastian Romero [2021-05-03]
\ No newline at end of file
diff --git a/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_frames_captured.png b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_frames_captured.png
new file mode 100644
index 00000000..d4b3eff0
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_frames_captured.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_attach_boards.svg b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_attach_boards.svg
new file mode 100644
index 00000000..6517a52e
--- /dev/null
+++ b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_attach_boards.svg
@@ -0,0 +1,922 @@
+
diff --git a/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_core.png b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_core.png
new file mode 100644
index 00000000..1fae5752
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_core.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_cover.svg b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_cover.svg
new file mode 100644
index 00000000..ce417d09
--- /dev/null
+++ b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_gs_cover.svg
@@ -0,0 +1,610 @@
+
diff --git a/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_open_pde_sketch.png b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_open_pde_sketch.png
new file mode 100644
index 00000000..4a8eef7c
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-ard-gs/assets/vs_ard_open_pde_sketch.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-gs/content.md b/content/tutorials/portenta-h7/vs-ard-gs/content.md
new file mode 100644
index 00000000..5d0d1b01
--- /dev/null
+++ b/content/tutorials/portenta-h7/vs-ard-gs/content.md
@@ -0,0 +1,382 @@
+---
+title: Getting Started With The Vision Shield Camera
+coverImage: assets/vs_ard_gs_cover.svg
+tags: [Getting Started, Camera, Processing, Serial]
+description: This tutorial shows you how to capture frames from the Vision Shield Camera module and visualise the video output through a Processing sketch.
+---
+
+# Getting Started With The Vision Shield Camera
+## Overview
+This tutorial shows you how to capture frames from the Vision Shield Camera module and visualise the video output through a Processing sketch.
+
+### You Will Learn
+- Capturing the frames from the camera.
+- Sending the frames as a byte stream through a Serial connection.
+- Visualising the frames in Processing.
+
+### Required Hardware and Software
+- 1x [Portenta H7 board](https://store.arduino.cc/portenta-h7)
+- 1x Portenta Vision Shield ( [LoRa](https://store.arduino.cc/portenta-vision-shield-lora) or [Ethernet](https://store.arduino.cc/portenta-vision-shield) )
+- 1x USB-C cable (either USB-A to USB-C or USB-C to USB-C)
+- Arduino IDE 1.8.10+
+- Processing 3.5.4+
+
+## Instructions
+Accessing the Vision Shield's camera data is done with the help of both Arduino and the Processing IDE. The Arduino sketch handles the capture of image data by the on-board camera while the java applet created with Processing helps to visualise this data with the help of a serial connection. The following steps will run you through how to capture, package the data through the serial port and visualise the output in Processing.
+
+### 1. The Basic Setup
+Connect the Vision Shield to your Portenta H7 as shown in the figure. The top and bottom high density connecters are connected to the corresponding ones on the underside of the H7 board. Plug in the H7 to your computer using the USB C cable.
+
+
+
+Open the board manager in the Arduino IDE and install the latest version of the Portenta Core which is [v1.3.2](https://github.com/arduino/ArduinoCore-mbed/releases/tag/1.3.2)
+
+
+
+### 2. Capturing the Frames
+
+Create a new Arduino sketch called `CameraCaptureRawBytes.ino`.
+
+To capture the frames you will need to use the functions contained in `camera.h` which comes with the Portenta core. This library contains all APIs related to frame capturing, motion detection and pattern recognition. Include the header file in your sketch.
+
+```cpp
+#include "camera.h"
+```
+
+Next, let's intialise a camera object and a frame buffer of the size 320*240 (76'800 bytes).
+
+```cpp
+CameraClass cam;
+uint8_t fb[320*240];
+```
+
+In the `setup()` function, let's start the Serial communication at `921600` baud rate and iniitialise the camera using `cam.begin()`.
+
+```cpp
+void setup() {
+ Serial.begin(921600);
+ //Init the cam QVGA, 30FPS
+ cam.begin(CAMERA_R320x240, 30);
+}
+```
+
+In the loop we need to capture each Frame and send it over a serial connection to the Processing sketch that will display the frames. We will use the `grab(uint8_t *buffer, uint32_t timeout=5000);` function to fetch the frame from the frame buffer and save it into our custom data buffer.
+
+```cpp
+void loop() {
+ // put your main code here, to run repeatedly:
+
+ // Wait until the receiver acknowledges
+ // that they are ready to receive new data
+ while(Serial.read() != 1){};
+
+ // Grab frame and write to serial
+ if (cam.grab(fb) == 0) {
+ Serial.write(fb, 320*240);
+ }
+
+}
+```
+
+### 3. Create the Processing Sketch
+Open a new processing sketch file and name it `CameraCapture.pde`.
+
+
+
+Let's start by importing the libraries and initialising the variables you will need to process the captured data. To process the data sent by the Vision Shield you will need to import the following libraries:
+
+- `processing.serial.*` : a [Serial Library](https://processing.org/reference/libraries/serial/index.html) that is used to read and write data to external devices over the serial line.
+- `java.nio.ByteBuffer` : a java class that provides access to operations on byte buffers
+
+```java
+import processing.serial.*;
+import java.nio.ByteBuffer;
+```
+
+Next we initialise the following variables to process the received pixels from the serial port. We set the dimensions, pixel count, and bytes required per frame.
+
+```java
+// must match resolution used in the sketch
+final int cameraWidth = 320;
+final int cameraHeight = 240;
+final int cameraBytesPerPixel = 1;
+final int cameraPixelCount = cameraWidth * cameraHeight;
+final int bytesPerFrame = cameraWidth * cameraHeight * cameraBytesPerPixel;
+```
+
+To recieve the frames you will need a Serial port, a PImage object and an array to store the pixel values of the frame. Add the following variables to the code.
+
+```java
+Serial myPort;
+PImage myImage;
+byte[] frameBuffer = new byte[bytesPerFrame];
+int pixelPosition = 0;
+int lastUpdate = 0;
+boolean shouldRedraw = false;
+```
+
+Here we will establish a connection to the serial port and prepare the buffer to store the frame pixels. Additionally we send a byte to the Arduino sketch from Processing to let it know that it's ready to receive data.
+
+```java
+void setup() {
+ size(640, 480);
+
+ // if you know the serial port name
+ //myPort = new Serial(this, "COM5", 921600); // Windows
+ //myPort = new Serial(this, "/dev/ttyACM0", 921600); // Linux
+ myPort = new Serial(this, "/dev/cu.usbmodem14101", 921600); // Mac
+
+ // Set the number of bytes to buffer
+ myPort.buffer(bytesPerFrame)
+
+ // Create an image based on the camera's dimensions and format
+ myImage = createImage(cameraWidth, cameraHeight, ALPHA);
+
+ // Let the Arduino sketch know we're ready to receive data
+ myPort.write(1);
+}
+```
+
+The draw function checks if the connection is still alive and if there is any new data that can be drawn as an image. In that case the original image gets copied into a new image object so that it can be scaled up.
+
+```java
+void draw() {
+ // Time out after 1.5 seconds and ask for new data
+ if(millis() - lastUpdate > 1500) {
+ println("Connection timed out.");
+ myPort.clear();
+ myPort.write(1);
+ }
+
+ if(shouldRedraw){
+ PImage img = myImage.copy();
+ img.resize(640, 480);
+ image(img, 0, 0);
+ shouldRedraw = false;
+ }
+}
+```
+
+### 4. Visualing the Frames
+For this step, you will use the `serialEvent()` callback function to update the `myImage` when a new data is received on the serial port.
+
+```java
+void serialEvent(Serial myPort) {
+ lastUpdate = millis();
+
+ // read the received bytes
+ myPort.readBytes(frameBuffer);
+
+ // Access raw bytes via byte buffer
+ ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
+
+ int i = 0;
+
+ while (bb.hasRemaining()) {
+ // read 8-bit pixel
+ byte pixelValue = bb.get();
+
+ // set pixel color
+ myImage.pixels[i++] = color(Byte.toUnsignedInt(pixelValue));
+ }
+
+ myImage.updatePixels();
+
+ // Ensures that the new image data is drawn in the next draw loop
+ shouldRedraw = true;
+
+ // Let the Arduino sketch know we received all pixels
+ // and are ready for the next frame
+ myPort.write(1);
+}
+```
+
+The first thing we do inside this method is to update the timestamp for when the last data was read. This is to detect and recover from a connection timeout. Then read the bytes from the `frameBuffer` array which you can do with the help of the [`readBytes()`](https://processing.org/reference/libraries/serial/Serial_readBytes_.html) method that returns the number of bytes read.
+
+```java
+lastUpdate = millis();
+
+// read the received bytes
+myPort.readBytes(frameBuffer);
+```
+
+Then the frame buffer is translated into a ByteBuffer that allows for easy and safe access to the underlying bytes without having to worry about the array indices.
+
+```cpp
+// Access raw bytes via byte buffer
+ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
+```
+
+Next we read the frame buffer and convert the bytes into pixel color values. The image gets constructed by sequentially filling the pixels array of the image. The conversion of the raw data is done wih [`color()`](https://processing.org/reference/color_.html) and [`Byte.toUnsignedInt()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Byte.html).
+
+```java
+int i = 0;
+
+while (bb.hasRemaining()) {
+ // read 8-bit pixel
+ byte pixelValue = bb.get();
+
+ // set pixel color
+ myImage.pixels[i++] = color(Byte.toUnsignedInt(pixelValue));
+}
+```
+
+Once all the pixels have been updated, you need to tell the sketch to redraw the image. Additionally we send an acknowledgement back to the arduino sketch to ask it to send the pixels for the next frame. We update the image with `updatePixels()` and write `1` to the serial port for the acknowledgement.
+
+``` cpp
+myImage.updatePixels();
+
+// Ensures that the new image data is drawn in the next draw loop
+shouldRedraw = true;
+
+// Let the Arduino sketch know we received all pixels
+// and are ready for the next frame
+myPort.write(1);
+```
+
+### 5. Upload the Sketch
+
+Select the right serial port on your IDE and upload the Arduino sketch to your H7. After a successful upload, run the `CameraViewer.pde` sketch in Processing. You should be able to see the rendered camera output on the Processing canvas.
+
+
+
+## Conclusion
+
+In this tutorial you learnt how to capture the frames from your Vision Shield's Camera and to visualise the frames throught Processing. This knowledge can be useful for you to build and experiment simple computer vision applications for both outdoor and indoor environments.
+
+### Complete Sketch
+The `CaptureRawBytes.ino` Sketch.
+
+```cpp
+#include "camera.h"
+
+CameraClass cam;
+uint8_t fb[320*240];
+
+void setup() {
+ Serial.begin(921600);
+
+ // Init the cam QVGA, 30FPS
+ cam.begin(CAMERA_R320x240, 30);
+}
+
+void loop() {
+ // put your main code here, to run repeatedly:
+
+ // Wait until the receiver acknowledges
+ // that they are ready to receive new data
+ while(Serial.read() != 1){};
+
+ // Grab frame and write to serial
+ if (cam.grab(fb) == 0) {
+ Serial.write(fb, 320*240);
+ }
+
+}
+```
+
+The `CameraViewer.pde` Sketch.
+
+```java
+/*
+ This sketch reads a raw Stream of RGB565 pixels
+ from the Serial port and displays the frame on
+ the window.
+ Use with the Examples -> CameraCaptureRawBytes Arduino sketch.
+ This example code is in the public domain.
+*/
+
+import processing.serial.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+Serial myPort;
+
+// must match resolution used in the sketch
+final int cameraWidth = 320;
+final int cameraHeight = 240;
+final int cameraBytesPerPixel = 1;
+final int cameraPixelCount = cameraWidth * cameraHeight;
+final int bytesPerFrame = cameraPixelCount * cameraBytesPerPixel;
+
+PImage myImage;
+byte[] frameBuffer = new byte[bytesPerFrame];
+int lastUpdate = 0;
+boolean shouldRedraw = false;
+
+void setup() {
+ size(640, 480);
+
+ // if you have only ONE serial port active
+ //myPort = new Serial(this, Serial.list()[0], 921600); // if you have only ONE serial port active
+
+ // if you know the serial port name
+ //myPort = new Serial(this, "COM5", 921600); // Windows
+ //myPort = new Serial(this, "/dev/ttyACM0", 921600); // Linux
+ myPort = new Serial(this, "/dev/cu.usbmodem14401", 921600); // Mac
+
+ // wait for full frame of bytes
+ myPort.buffer(bytesPerFrame);
+
+ myImage = createImage(cameraWidth, cameraHeight, ALPHA);
+
+ // Let the Arduino sketch know we're ready to receive data
+ myPort.write(1);
+}
+
+void draw() {
+ // Time out after 1.5 seconds and ask for new data
+ if(millis() - lastUpdate > 1500) {
+ println("Connection timed out.");
+ myPort.clear();
+ myPort.write(1);
+ }
+
+ if(shouldRedraw){
+ PImage img = myImage.copy();
+ img.resize(640, 480);
+ image(img, 0, 0);
+ shouldRedraw = false;
+ }
+}
+
+void serialEvent(Serial myPort) {
+ lastUpdate = millis();
+
+ // read the received bytes
+ myPort.readBytes(frameBuffer);
+
+ // Access raw bytes via byte buffer
+ ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
+
+ /*
+ Ensure proper endianness of the data for > 8 bit values.
+ When using > 8bit values uncomment the following line and
+ adjust the translation to the pixel color.
+ */
+ //bb.order(ByteOrder.BIG_ENDIAN);
+
+ int i = 0;
+
+ while (bb.hasRemaining()) {
+ // read 8-bit pixel
+ byte pixelValue = bb.get();
+
+ // set pixel color
+ myImage.pixels[i++] = color(Byte.toUnsignedInt(pixelValue));
+ }
+
+ myImage.updatePixels();
+
+ // Ensures that the new image data is drawn in the next draw loop
+ shouldRedraw = true;
+
+ // Let the Arduino sketch know we received all pixels
+ // and are ready for the next frame
+ myPort.write(1);
+}
+```
+
+**Authors:** Lenard George, Sebastian Romero
+**Reviewed by:** Sebastian Romero [2021-04-26]
+**Last revision:** Sebastian Romero [2021-04-26]
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_add_app.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_add_app.png
index 6e321924..79407f45 100644
Binary files a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_add_app.png and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_add_app.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_app.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_app.png
index 8cb212ad..38edc6dd 100644
Binary files a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_app.png and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_app.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_app_param.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_app_param.png
index 9e735b2e..fdf258e3 100644
Binary files a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_app_param.png and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_app_param.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_click_register.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_click_register.png
index f773a3c2..d60b929e 100644
Binary files a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_click_register.png and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_click_register.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_device_overview.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_device_overview.png
index 34337e97..9da5d782 100644
Binary files a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_device_overview.png and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_device_overview.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_home.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_home.png
index 6689bb5d..671a6b49 100644
Binary files a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_home.png and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_home.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_new_app.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_new_app.png
deleted file mode 100644
index 74fb7a26..00000000
Binary files a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_new_app.png and /dev/null differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device.png
deleted file mode 100644
index 25e506c4..00000000
Binary files a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device.png and /dev/null differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device_1.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device_1.png
new file mode 100644
index 00000000..fa057cd7
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device_1.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device_2.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device_2.png
new file mode 100644
index 00000000..eb4fe571
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_register_device_2.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_serial.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_serial.png
new file mode 100644
index 00000000..7a3f3491
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_serial.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_standalone.png b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_standalone.png
new file mode 100644
index 00000000..f14271d2
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-ard-ttn/assets/vs_ard_ttn_standalone.png differ
diff --git a/content/tutorials/portenta-h7/vs-ard-ttn/content.md b/content/tutorials/portenta-h7/vs-ard-ttn/content.md
index 7112f741..69f97221 100644
--- a/content/tutorials/portenta-h7/vs-ard-ttn/content.md
+++ b/content/tutorials/portenta-h7/vs-ard-ttn/content.md
@@ -25,7 +25,23 @@ This tutorial explains how to connect your Portenta H7 to The Things Network (TT
- [1x Dipole Pentaband antenna](https://store.arduino.cc/antenna) or a UFL Antenna of the H7
- Arduino [offline](https://www.arduino.cc/en/main/software) IDE or Arduino ([Web Editor](https://create.arduino.cc/)
- USB C cable (either USB A to USB C or USB C to USB C)
-- An [account](https://account.thethingsnetwork.org/users/login) with The Things Network
+- An [account](https://console.cloud.thethings.network/) with The Things Network
+
+### Updating the LoRa® Module Firmware
+To be able to use the LoRa® functionality, we need to first update the firmware on the LoRa® modem. This can be done through Arduino IDE by running a sketch included in the examples from the MKRWAN library.
+
+1. Connect the Portenta H7 and the Portenta Vision Shield to your computer and open the Arduino IDE.
+2. Install/update the **MKRWAN** library from Arduino IDE menu **Tools > Manage Libraries**. Type "MKRWAN" to find the library and click 'Install' or 'Update' if necessary. This library provides all the APIs to communicate with LoRa® and LoRaWAN® networks.
+3. Open the **MKRWANFWUpdate_standalone** sketch from the Arduino IDE menu: **File > Examples > MKRWAN**.
+
+4. Upload the sketch.
+
+
+
+
+5. Open the serial monitor and wait for the update to be confirmed.
+
+
## Connecting to the TTN
@@ -33,37 +49,35 @@ The Portenta Vision Shield - LoRa® can be connected to the TTN and can transmit
### 1. Setting up the Environment
-Start by pointing your browser to www.thethingsnetwork.org and use the Sign Up button to setup an account. Next, then fill all the required fields to complete a new registration (if you already have a TTN account, skip this step and continue by signing in).
+Start by going [here](https://console.cloud.thethings.network/). First choose your region. Next, sign in with your The Things Network account. If you don't have an account, create a new one on the login page. Then fill all the required fields to complete a new registration.

### 2. Creating an App on TTN
-Once you have created an account with TTN, you need to create a TTN [application](https://www.thethingsnetwork.org/docs/applications/). An application provides a way to aggregate data from different devices, and then use these data with other 3rd party integrations. Go to your [console](https://console.thethingsnetwork.org), and click on **Applications**
+Once you have created an account with TTN, you need to create a TTN [application](https://www.thethingsnetwork.org/docs/applications/). An application provides a way to aggregate data from different devices, and then use these data with other 3rd party integrations. After signing in, click on **Create an application**, or **Go to applications** if you already have one created.

-Here you'll have a list of all your applications. Now create your first app by pressing the **add application** button.
-
-
+Here you'll have a list of all your applications. Now create your first app by pressing the **Create an application** button.
You have now to fill only the first two fields:
-- The first one is the **ID** of your app: this must be lowercase and without spaces.
-- The second one is a **Description** of your app, and there's no restrictions on formatting
+- The first one is the **Owner** of your app, it will automatically have you as the owner.
+- The second one is the **ID** of your app: this must be lowercase and without spaces.

-After completing these two fields, press on the "Add application" button located at the bottom right corner of the page. The dashboard will then show you an overview of the newly created app.
+After completing these two fields, press the "Create application" button located at the bottom left corner of the page. The dashboard will then show you an overview of the newly created app.

Let's take a closer look at these sections:
-- **Application Overview** and Application EUIS: in order to use this app, you'll need the Application ID and its EUIs. An EUI is a globally unique identifier for networks, gateways applications and devices. The EUIs are used to identify all parts of the LoRaWAN® inside the backend server.
-- **Devices**: here you can see and manage all the associated devices (e.g. your Portenta H7 with Vision Shield LoRa®, Arduino MKR WAN 1300 or MKR WAN 1310), or proceed with the registration of new one.
+- **Application Overview**: in order to use this app, you'll need the Application ID and a device specific AppKey. An EUI is a globally unique identifier for networks, gateways applications and devices. The EUIs are used to identify all parts of the LoRaWAN inside the backend server.
+- **End devices**: here you can see and manage all the associated devices (e.g. your Portenta H7 with Vision Shield LoRa, Arduino MKR WAN 1300 or MKR WAN 1310), or proceed with the registration of a new one. Registering a new device lets you generate an AppEUI and an AppKey.
- **Collaborators**: here you can see and manage all the app collaborators. To integrate with other collaborative platforms or to manage access rights to the app with other TTN registered profiles.
-- **Access keys**: it's the most sensible information. It is basically the key to gain access to your app, so keep it safe.
+- **API keys**: here you can create an API key, it's the most sensible information. It is basically the key to gain access to your app, so keep it safe.
### 3. Configuring the Vision Shield
@@ -100,14 +114,19 @@ In order to select the way in which the board is going to connect with TTN (OTA
### 4. Registring the Portenta on TTN
-Before your Portenta H7 can start communicating with the TTN you need to [register](https://www.thethingsnetwork.org/docs/devices/registration.html) the board with an application. Go back to the TTN portal and scroll to **Devices** section on your Application dashboard, then click **Register Device**.
+Before your Portenta H7 can start communicating with the TTN you need to [register](https://www.thethingsnetwork.org/docs/devices/registration.html) the board with an application. Go back to the TTN portal and scroll to **End devices** section on your Application dashboard, then click **Add end device**.

-On the registration page, fill in **Device ID** and **EUI**.
-**Note**: The Device ID must be lowercase and without spaces. The **EUI** should be copied from the Serial Monitor.
+On the registration page, first we have to fill in information about our board. Select brand Arduino SA, and Portenta Vision Shield LoRa as the model. Hardware and firmware versions will automatically be set to the newest ones. Then set your preferred region.
+
+
+
+In the second step of registering the device, fill in **End device ID** and **DevEUI**. You can click the generate button next to the AppKey field to generate an app key for this device. Similarly, you can press the button next to the AppEUI field to make it all zeros, or enter your own AppEUI.
+
+**Note**: The Device ID must be lowercase and without spaces. The **DevEUI** should be copied from the Serial Monitor.
-
+
After pressing the Register button, your board will show up on the **Device Overview** page. You can now see all the information needed to complete the Arduino setup.
@@ -117,7 +136,7 @@ After pressing the Register button, your board will show up on the **Device Over
Once your board has been registered you can send information to TTN. Let's come back to the Serial Monitor and proceed. It will ask for:
-- Activation mode (that, in this case, is OTAA as you can see in the screenshot above),
+- Activation mode (that, in this case, is OTAA),
- The Application EUI
- The App Key.
@@ -156,4 +175,4 @@ If we are within good range of a gateway, we should also try to move our device
**Authors:** Lenard George, Ignacio Herrera
**Reviewed by:** Jose Garcia, Linnea Åkerberg [2021-02-02]
-**Last revision:** Sebastian Romero [2021-02-05]
\ No newline at end of file
+**Last revision:** Benjamin Dannegård [2021-05-21]
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/por_ard_gs_upload_sketch.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/por_ard_gs_upload_sketch.png
new file mode 100644
index 00000000..605d9125
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/por_ard_gs_upload_sketch.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_add_app.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_add_app.png
new file mode 100644
index 00000000..79407f45
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_add_app.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_app.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_app.png
new file mode 100644
index 00000000..38edc6dd
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_app.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_app_param.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_app_param.png
new file mode 100644
index 00000000..fdf258e3
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_app_param.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_click_register.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_click_register.png
new file mode 100644
index 00000000..d60b929e
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_click_register.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_device_overview.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_device_overview.png
new file mode 100644
index 00000000..9da5d782
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_device_overview.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_home.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_home.png
new file mode 100644
index 00000000..671a6b49
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_home.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_register_device_1.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_register_device_1.png
new file mode 100644
index 00000000..fa057cd7
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_register_device_1.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_register_device_2.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_register_device_2.png
new file mode 100644
index 00000000..eb4fe571
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_ard_ttn_register_device_2.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_select_example.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_select_example.png
new file mode 100644
index 00000000..f14271d2
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_select_example.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_ttn_cover.svg b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_ttn_cover.svg
new file mode 100644
index 00000000..5303c0a0
--- /dev/null
+++ b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_ttn_cover.svg
@@ -0,0 +1,1289 @@
+
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_ttn_serialmonitor.png b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_ttn_serialmonitor.png
new file mode 100644
index 00000000..7a3f3491
Binary files /dev/null and b/content/tutorials/portenta-h7/vs-openmv-ttn/assets/vs_mp_ttn_serialmonitor.png differ
diff --git a/content/tutorials/portenta-h7/vs-openmv-ttn/content.md b/content/tutorials/portenta-h7/vs-openmv-ttn/content.md
new file mode 100644
index 00000000..bc0c0630
--- /dev/null
+++ b/content/tutorials/portenta-h7/vs-openmv-ttn/content.md
@@ -0,0 +1,241 @@
+---
+title: Connecting to The Things Network Using OpenMV
+coverImage: assets/vs_mp_ttn_cover.svg
+tags: [Getting Started, OpenMV, IDE, Setup, TTN, LoRa]
+description: This tutorial explains how to connect your Portenta H7 to The Things Network (TTN) using the Vision Shield's LoRa Connectivity feature.
+---
+
+# Connecting to The Things Network Using OpenMV
+## Overview
+
+This tutorial explains how to connect your Portenta H7 to The Things Network (TTN) using the Vision Shield's LoRa Connectivity feature. A data communication channel will be enabled between the H7 and a TTN application that will be configured on your TTN console.
+
+***In order to connect your Portenta to the TTN make sure you are within the range (max. 10 Km) from an available LoRa Gateway. Indoor gateways will have a much shorter range. It is recommended that you check LoRa Gateway availability on [The Things Network map](https://www.thethingsnetwork.org/map) before you try this tutorial.***
+
+### You Will Learn
+
+- About LoRaWAN® and The Things Network,
+- About creating a TTN application,
+- How to establish a connection between the H7 and the TTN,
+
+### Required Hardware and Software
+
+- 1 x [Portenta H7 board](https://store.arduino.cc/portenta-h7)
+- 1 x [Portenta Vision Shield - LoRa](https://store.arduino.cc/portenta-vision-shield-lora)
+- [1x Dipole Pentaband antenna](https://store.arduino.cc/antenna) or a UFL Antenna of the H7
+- [OpenMV IDE](https://openmv.io/pages/download)
+- Arduino IDE 1.8.10+ or Arduino Pro IDE 0.0.4+ or Arduino CLI 0.13.0+
+- 1 x USB-C cable (either USB-A to USB-C or USB-C to USB-C)
+- An [account on The Things Network](https://console.cloud.thethings.network/)
+
+## Instructions
+
+The Portenta Vision Shield - LoRa can be connected to the TTN and can transmit data to other devices connected to this network through a secure channel. This channel is nothing but an application on the TTN network dedicated for your board. In this tutorial, you will be guided through a step-by-step process of setting up your Portenta board and the Vision Shield LoRa to communicate with a TTN application using OpenMV and MicroPython. As stated before, to be able to follow this guide, to be under coverage of one of the TTN gateways. You can check for [the coverage](https://www.thethingsnetwork.org/map) now if you have not done so yet.
+
+### 1. Setting up the Environment
+
+Start by going [here](https://console.cloud.thethings.network/). First choose your region. Next, sign in with your The Things Network account, or create a new one on the login page.
+
+
+
+### 2. Creating an App on TTN
+
+Once you have created an account with TTN, you need to create a TTN [application](https://www.thethingsnetwork.org/docs/applications/). An application provides a way to aggregate data from different devices, and then use these data with other 3rd party integrations. After signing in, click on **Create an application**, or **Go to applications** if you already have one created.
+
+
+
+Here you'll have a list of all your applications. Now create your first app by pressing the **Create an application** button.
+
+You have now to fill only the first two fields:
+
+- The first one is the **Owner** of your app, it will automatically have you as the owner.
+- The second one is the **ID** of your app: this must be lowercase and without spaces.
+
+
+
+After completing these two fields, press the "Create application" button located at the bottom left corner of the page. The dashboard will then show you an overview of the newly created app.
+
+
+
+Let's take a closer look at these sections:
+
+- **Application Overview**: in order to use this app, you'll need the Application ID and a device specific AppKey. An EUI is a globally unique identifier for networks, gateways applications and devices. The EUIs are used to identify all parts of the LoRaWAN inside the backend server.
+- **End devices**: here you can see and manage all the associated devices (e.g. your Portenta H7 with Vision Shield LoRa, Arduino MKR WAN 1300 or MKR WAN 1310), or proceed with the registration of a new one. Registering a new device lets you generate an AppEUI and an AppKey.
+- **Collaborators**: here you can see and manage all the app collaborators. To integrate with other collaborative platforms or to manage access rights to the app with other TTN registered profiles.
+- **API keys**: here you can create an API key, it's the most sensible information. It is basically the key to gain access to your app, so keep it safe.
+
+### 3. Updating the Modems Firmware
+
+To be able to use the LoRa functionality, we need to first update the modems firmware through the Arduino IDE. Connect the Portenta and Vision shield to your computer and open the Arduino IDE. The LoRa module on the Vision Shield can be accessed by using the [MKRWAN library](https://github.com/arduino-libraries/MKRWAN)(if you can't find it in your examples list, you can go to **tools > library manager** and type "MKRWAN library" to install it). This library provides all the APIS to communicate with LoRa and LoRaWAN networks and can be installed from the library manager. Select the **Portenta H7 (M7 core)** board in the Arduino IDE, like shown below.
+
+
+
+The code you need to upload and run is from the **MKRWAN** library, and its name is **MKRWANFWUpdate_standalone**. With the Portenta M7 selected, upload the **MKRWANFWUpdate_standalone** sketch.
+
+
+
+After uploading the sketch, open the serial monitor to confirm that the firmware has been updated. If the upload was successful it will print the progress in the serial monitor.
+
+
+
+If it all went correctly, you should see the same text in your serial monitor as on the image above.
+
+### 4. Configuring the Vision Shield
+
+It's now time to connect your Portenta H7 and LoRa Vision Shield to TTN. You'll need to upload code to the board using [OpenMV](https://openmv.io/pages/download)
+
+Plug the Portenta Vision Shield - LoRa to the Portenta H7 and them to your PC through the USB port. If the Portenta board does not show up on OpenMV, try double-pressing the reset button on the Portenta. And now update to the latest firmware in OpenMV.
+
+The only line you may need to change before uploading the code is the one that sets the frequency. Set the frequency code according to your country if needed. You can find more information about frequency by country at [this TTN link](https://www.thethingsnetwork.org/docs/lorawan/frequency-plans.html).
+
+***Consider that in Australia the boards connect correctly to TTN gateways on AS923 frequencies; AU915 frequencies requires the selection of sub band 2 which is not yet implemented in the firmware.***
+
+```py
+// change this to your regional band (eg. US915, AS923, ...)
+lora = Lora(band=BAND_EU868, poll_ms=60000, debug=False)
+```
+
+The `lora.join_OTAA()` or `lora.join_ABP()` functions connect your vision shield to the things network (TTN), using either Over-The-Air-Activation (OTAA) or Activating-By-Personalization (ABP) protocols. We just need to enter our `appEui` and `appKey`. The timeout decides how long the board will try and connect before stopping.
+
+```py
+try:
+ lora.join_OTAA(appEui, appKey, timeout=20000)
+ # Or ABP:
+ #lora.join_ABP(devAddr, nwkSKey, appSKey, timeout=5000)
+```
+
+We can then send data to our TTN application with `lora.send_data()`, in here we can decide what data we want to send to our TTN application.
+
+```py
+try:
+ if lora.send_data("HeLoRA world!", True):
+ print("Message confirmed.")
+ else:
+ print("Message wasn't confirmed")
+```
+
+Now we need to read the downlink message. Using the `lora.available()` function we check if there is data received on the board. If there is data on the board that has been received, we can use the `lora.receive_data()` function to take that data and put it into a local variable. Making it easier to print in the OpenMV IDE serial terminal. Using `lora.poll()` we can make sure that the LoRa module is ready before we run the loop again.
+
+```py
+# Read downlink messages
+while (True):
+ if (lora.available()):
+ data = lora.receive_data()
+ if data:
+ print("Port: " + data["port"])
+ print("Data: " + data["data"])
+ lora.poll()
+ sleep_ms(1000)
+```
+
+**Hint: The Complete Sketch can be found in the Conclusions**
+
+Then, once the upload is completed open the Serial Terminal where you can now see firmware info, device EUI, data rate and join status.
+
+In order to select the way in which the board is going to connect with TTN (OTAA or ABP) we need to configure it on the TTN portal. We will see which option we should select in the following steps.
+
+### 5. Registering the Portenta on TTN
+
+Before your Portenta H7 can start communicating with the TTN you need to [register](https://www.thethingsnetwork.org/docs/devices/registration.html) the board with an application. Go back to the TTN portal and scroll to **End devices** section on your Application dashboard, then click **Add end device**.
+
+
+
+On the registration page, first we have to fill in information about our board. Select brand Arduino SA, and Portenta Vision Shield LoRa as the model. Hardware and firmware versions will automatically be set the newest ones. Then set your preferred region.
+
+
+
+In the second step of registering the device, fill in **End device ID** and **EUI**. You can click the generate button next to the AppKey field to generate an app key for this device. Similarly, you can press the button next to the AppEUI field to make it all zeros, or enter your own AppEUI.
+
+**Note**: The Device ID must be lowercase and without spaces. The **DevEUI** can be copied from the terminal in OpenMV. You can run the following script to obtain it.
+
+```py
+from lora import *
+print("Device EUI:", Lora().get_device_eui())
+```
+
+
+
+After pressing the Register button, your board will show up on the **Device Overview** page. You can now see all the information needed to complete the Arduino setup.
+
+
+
+### 6. Connecting to TTN
+
+Once your board has been registered you can send information to TTN. Let's go back to the sketch to fill in the appEui and appKey. The sketch we use here will use OTA connection.
+
+You can read more into OTA vs ABP activation mode at [this link](https://www.thethingsnetwork.org/docs/devices/registration.html)
+
+Once your board has been registered you can send information to TTN. Let's proceed in OpenMV. In the sketch the application EUI and the app key needs to be filled in. Find the EUI and the App key from TTN **Device Overview** page.
+
+If this process is done successfully, you will see this message:
+
+```text
+Message confirmed.
+```
+
+## Conclusion
+If you receive this message, you have managed to configure the Portenta H7 and the LoRa Vision Shield on the TTN. We have retrieved the device EUI, used it to register the device in the TTN console, and programmed the board using the data provided by TTN. Now, we can send data over the LoRa® network which can be viewed from anywhere in the world (as long as we have an Internet connection and our device is in range from a TTN gateway).
+
+### Complete Sketch
+
+```py
+from lora import *
+
+lora = Lora(band=BAND_EU868, poll_ms=60000, debug=False)
+
+print("Firmware:", lora.get_fw_version())
+print("Device EUI:", lora.get_device_eui())
+print("Data Rate:", lora.get_datarate())
+print("Join Status:", lora.get_join_status())
+
+appEui = "" # Add your App EUI here
+appKey = "" # Add your App Key here
+
+try:
+ lora.join_OTAA(appEui, appKey, timeout=20000)
+ # Or ABP:
+ #lora.join_ABP(devAddr, nwkSKey, appSKey, timeout=5000)
+# You can catch individual errors like timeout, rx etc...
+except LoraErrorTimeout as e:
+ print("Something went wrong; are you indoor? Move near a window and retry")
+ print("ErrorTimeout:", e)
+except LoraErrorParam as e:
+ print("ErrorParam:", e)
+
+print("Connected.")
+lora.set_port(3)
+
+try:
+ if lora.send_data("HeLoRA world!", True):
+ print("Message confirmed.")
+ else:
+ print("Message wasn't confirmed")
+
+except LoraErrorTimeout as e:
+ print("ErrorTimeout:", e)
+
+# Read downlink messages
+while (True):
+ if (lora.available()):
+ data = lora.receive_data()
+ if data:
+ print("Port: " + data["port"])
+ print("Data: " + data["data"])
+ lora.poll()
+ sleep_ms(1000)
+```
+
+### Next Steps
+
+- Experiment your Vision Shield's capabilities with OpenMV and the examples from the dedicated library for Arduino. You can continue with [this tutorial](https://www.arduino.cc/pro/tutorials/portenta-h7/por-openmv-bt) from the Arduino Pro site.
+- Combine LoRaWAN protocol with an OpenMV example to develop your own IoT application. Take advantage of the Vision Shield's camera to detect, filter, classify images, read QR codes or more.
+
+## Troubleshooting
+
+The most common issue is that the device cannot connect to a TTN gateway. Again, it is a good idea to check if we have coverage in the area we are conducting this tutorial, by checking out [this map](https://www.thethingsnetwork.org/map).
+
+If we are within good range of a gateway, we should also try to move our device and antenna to a window, and even hold it out the window and move it around. This has proven successful on numerous accounts, as the signal can travel less obstructed.
+
+**Authors:** Lenard George, Ignacio Herrera, Benjamin Dannegård
+**Reviewed by:** Lenard George [2021-05-07]
+**Last revision:** Benjamin Dannegård [2021-05-07]
diff --git a/generate-datasheets b/generate-datasheets
deleted file mode 100755
index 59af2a8c..00000000
--- a/generate-datasheets
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-if ! command -v node &> /dev/null
-then
- echo "Please install Node.js from here https://nodejs.org/en/download/"
- exit
-fi
-
-cd scripts/datasheet-generator
-npm list --depth=0 > /dev/null 2>&1
-
-if [ $? -ne 0 ]; then
- echo "Installing node modules..."
- npm install
-fi
-
-node generate-datasheets.js "../../content/datasheets" "../../build/datasheets"
\ No newline at end of file
diff --git a/scripts/datasheet-generator/README.md b/scripts/datasheet-generator/README.md
deleted file mode 100644
index 5ad5314e..00000000
--- a/scripts/datasheet-generator/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Datasheet-Infrastructure
-
-This tool allows for creating datasheet-PDFs from a markdown file.
-
-## Installation
-- Nodejs & npm have to be installed.
-- Install dependencies via ```npm install```
-
-## Create a new datasheet
-- Within the directory ```/content```, create a folder for the new datasheet
-- In your newly created folder create the ```content.md``` file that includes the content of the datasheet as well as a subfolder called ```assets```
-
-## Automated creations
-- The first picture in the ```content.md``` file will be used as title picture on the front page eg. ``````
-- The sections `#Description, #Target areas & #Features` will be part of the front page
-- Create the `# Contents` section. This section is special, **no content should be added in this section**, it will be created **automatically**
-
-## Pictures & picture descriptions
-- jpg, png, svg are the recommended file formats
-- Picture without a description element underneath: ``
-- Picture with a description element underneath: ``
-
-## Handling table elements
-Not a must in terms of the correct compilation of a MD datasheet, but still recommended for readability purposes, is using a **markdown table prettifier** such as the [darkriszty.markdown-table-prettify](https://marketplace.visualstudio.com/items?itemName=darkriszty.markdown-table-prettify) extension for Visual Studio Code or using *visual* markdown editors such as [Typora](https://typora.io/).
-
-## Compile the datasheet
-This is relevant if wanting to compiling the datasheets offline:
-1. `cd scripts`
-2. `node generate-datasheets.js`
\ No newline at end of file
diff --git a/scripts/datasheet-generator/datasheet-generator.js b/scripts/datasheet-generator/datasheet-generator.js
deleted file mode 100644
index d3768da1..00000000
--- a/scripts/datasheet-generator/datasheet-generator.js
+++ /dev/null
@@ -1,309 +0,0 @@
-const marked = require('marked')
-const fm = require('front-matter')
-const fs = require('fs')
-const path = require('path');
-const jsdom = require('jsdom')
-const pdf = require('html-pdf')
-const util = require('util')
-const pdfParser = require('pdf-parse')
-const express = require('express')
-
-const SERVER_PORT = 8000
-const STYLES_PATH = "../datasheet-generator/styles"
-const SUBTITLE = "Product Reference Manual"
-
-//console.log(util.inspect(contentIndex, {showHidden: false, depth: null}))
-
-const readFile = util.promisify(fs.readFile)
-const writeFile = util.promisify(fs.writeFile)
-const createPdf = util.promisify(pdf.create)
-
-let contentListText = []
-let contentListMap = []
-
-const numberHeadings = (dom) => {
- let contentIndex = { H2:0, H3:0, H4:0, H5:0, H6:0 }
-
- // add content list section
- contentTitle = dom.window.document.getElementById("contents")
- let contentList = dom.window.document.createElement("div")
- addNodeAfter(contentTitle, contentList)
-
- dom.window.document.querySelectorAll("h2, h3, h4, h5, h6").forEach(element => {
- contentIndex[element.nodeName]++
- element.textContent = ' ' + element.textContent
-
- switch(element.nodeName) {
- case "H6":
- element.textContent = '.' + contentIndex.H6 + element.textContent
- case "H5":
- element.textContent = '.' + contentIndex.H5 + element.textContent
- case "H4":
- element.textContent = '.' + contentIndex.H4 + element.textContent
- case "H3":
- element.textContent = '.' + contentIndex.H3 + element.textContent
- case "H2":
- element.textContent = contentIndex.H2 + element.textContent
- }
-
- // temporary save header text for future calculation of page numbers
- contentListText.push(element.textContent)
-
- switch(element.nodeName) {
- case "H2":
- contentIndex.H3 = 0
- case "H3":
- contentIndex.H4 = 0
- case "H4":
- contentIndex.H5 = 0
- case "H5":
- contentIndex.H6 = 0
- }
-
- addElementToContentIndex(dom, contentList, element)
- })
-}
-
-const prepareTitlePage = (dom) => {
- let outerList = dom.window.document.querySelector("ul")
- outerList.setAttribute("id", "feature-list")
-}
-
-const addElementToContentIndex = (dom, contentList, element) => {
- let contentItem = dom.window.document.createElement('div')
- contentList.setAttribute("id", "table-of-contents");
- //let link = dom.window.document.createElement('a')
- let linkText = dom.window.document.createTextNode(element.textContent)
-
- contentItem.classList.add('list-' + element.nodeName)
- //link.title = element.textContent
- //link.href = "#" + element.id
- //link.appendChild(linkText)
- contentItem.appendChild(linkText)
- contentList.appendChild(contentItem)
- contentListMap.push({
- id: element.textContent,
- pageNumber: 0,
- item: contentItem
- })
-}
-
-const addPageNumberToContentList = (dom, contentList) => {
- contentList.forEach(element => {
- let numberItem = dom.window.document.createElement('div')
- numberItem.setAttribute("class", "page-number");
- numberItem.innerHTML = element.pageNumber
- element.item.appendChild(numberItem)
- element.item.nodeValue = element.item.nodeValue
- })
-}
-
-const addNodeAfter = (rootElement, newElement) => {
- rootElement.parentNode.insertBefore(newElement, rootElement.nextSibling)
-}
-
-const createHtml = (mdContent) => {
- // convert md to dom-nodes
- const htmlContent = marked(mdContent)
- let dom = new jsdom.JSDOM(htmlContent)
-
- // number sections + create content index
- numberHeadings(dom)
-
- // add IDs to special sections
- prepareTitlePage(dom)
-
- // add descriptions underneath illustrations
- addIllustrationDescriptions(dom)
-
- return dom
-}
-
-const addIllustrationDescriptions = (dom) => {
- dom.window.document.querySelectorAll("img").forEach(element => {
- const descriptionString = element.alt
-
- if (descriptionString && descriptionString.length > 0) {
- let descriptionElement = dom.window.document.createElement("div")
- descriptionElement.innerHTML = descriptionString
- descriptionElement.classList.add('img-description')
- addNodeAfter(element, descriptionElement)
- }
- })
-}
-
-const injectData = (dom, identifier, cssContent) => {
-
- // Inject CSS styles
- let style = dom.window.document.createElement("style")
- style.appendChild(dom.window.document.createTextNode(cssContent))
- dom.window.document.head.appendChild(style)
-
- // Inject Subtitle
- let subtitle = dom.window.document.createElement("div")
- subtitle.innerHTML = `${SUBTITLE} SKU: ${identifier}`
- subtitle.classList.add("subtitle")
- dom.window.document.body.prepend(subtitle)
-
- return dom.serialize()
-}
-
-const writeContent = async (filename, content) => {
- return writeFile(filename, content)
-}
-
-const readContent = async (path) => {
- return readFile(path, 'utf8')
-}
-
-const preparePdfProperties = (style, contentURL, pdfFilename, boardName, revisionNumber) => {
- const specificLogoSVGdata = fs.readFileSync(`${STYLES_PATH}/${style}-logo.svg`)
- let options = {
- format: 'A4',
- filename: pdfFilename,
- "base": contentURL,
- "border": {
- "right": "20mm",
- "left": "20mm"
- }
- }
-
- options.footer = {
- "height": "28mm",
- "contents": {
- first: ' ',
- default: `
-
-