From 4e3c7fe46a9704ed70504e097bc8d97c9743637f Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 12 Jun 2020 20:43:49 +0200 Subject: [PATCH 01/88] Added instructions for balena.io deployment --- .gitignore | 3 + Dockerfile | 1 + Dockerfile.template | 21 +++++ README-balena.md | 103 +++++++++++++++++++++++++ README.md | 13 ++++ balena.yml | 6 ++ examples/live-s2.sm.tc/cups-boot.crt | 11 --- examples/live-s2.sm.tc/cups-boot.key | 5 -- examples/live-s2.sm.tc/cups-boot.trust | 11 --- examples/live-s2.sm.tc/cups-boot.uri | 1 - examples/live-s2.sm.tc/makefile | 2 +- examples/live-s2.sm.tc/tc.trust | 20 +++++ examples/live-s2.sm.tc/tc.uri | 2 + setup.gmk | 16 ++-- start.sh | 49 ++++++++++++ 15 files changed, 228 insertions(+), 36 deletions(-) create mode 100644 .gitignore create mode 100644 Dockerfile.template create mode 100644 README-balena.md create mode 100644 balena.yml delete mode 100644 examples/live-s2.sm.tc/cups-boot.crt delete mode 100644 examples/live-s2.sm.tc/cups-boot.key delete mode 100644 examples/live-s2.sm.tc/cups-boot.trust delete mode 100644 examples/live-s2.sm.tc/cups-boot.uri create mode 100644 examples/live-s2.sm.tc/tc.trust create mode 100644 examples/live-s2.sm.tc/tc.uri create mode 100644 start.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4668c4b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +deps/.DS_Store +.DS_Store diff --git a/Dockerfile b/Dockerfile index 1926cac6..5b81934c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,3 +30,4 @@ RUN sudo apt-get install --no-install-recommends -yq \ RUN pip3 install aiohttp websockets + diff --git a/Dockerfile.template b/Dockerfile.template new file mode 100644 index 00000000..3d3f8f7c --- /dev/null +++ b/Dockerfile.template @@ -0,0 +1,21 @@ +FROM balenalib/%%BALENA_MACHINE_NAME%%-debian:stretch + +# Install build tools and remove layer cache afterwards +RUN apt-get -q update && apt-get install -yq --no-install-recommends \ + build-essential \ + git \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +RUN install_packages jq + +# Switch to working directory for our app +WORKDIR /usr/src/app + +# Copy all the source code in. +COPY . . + +# Compile our source code +RUN make platform=rpi variant=std arch=%%BALENA_ARCH%% + +# Launch our binary on container startup. +CMD ["bash", "start.sh"] diff --git a/README-balena.md b/README-balena.md new file mode 100644 index 00000000..5b0533dc --- /dev/null +++ b/README-balena.md @@ -0,0 +1,103 @@ +# LoRa Basics™ Station using balena.io and RAK2245 + +This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 Pi Hat. + + +## Introduction + +Deploy a The Things Network (TTN) LoRa gateway running the basics station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. + +The Basics Station protocol enables the LoRa gateways with a reliable and secure communication between the gateways and the cloud and it is becoming the standard Packet Forward protocol used by most of the LoRaWAN operators. + + +## Getting started + +### Hardware + +* Raspberry Pi 4 or [balenaFin](https://www.balena.io/fin/) +* [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) +* SD card in case of the RPi 4 + +### Software + +* A TTN account ([sign up here](https://console.thethingsnetwork.org) +* A balenaCloud account ([sign up here](https://dashboard.balena-cloud.com/) +* [balenaEtcher](https://balena.io/etcher) + +Once all of this is ready, you are able to deploy this repository following instructions below. + +## Deploy the code + +### Via [Balena Deploy](https://www.balena.io/docs/learn/deploy/deploy-with-balena-button/) + +Running this project is as simple as deploying it to a balenaCloud application. You can do it in just one click by using the button below: + +[![](https://www.balena.io/deploy.png)](https://dashboard.balena-cloud.com/deploy?repoUrl=https://github.com/balena-io-playground/basicstation) + +Follow instructions, click Add a Device and flash an SD card with that OS image dowloaded from balenaCloud. Enjoy the magic 🌟Over-The-Air🌟! + + +### Via [Balena-Cli](https://www.balena.io/docs/reference/balena-cli/) + +If you are a balena CLI expert, feel free to use balena CLI. + +- Sign up on [balena.io](https://dashboard.balena.io/signup) +- Create a new application on balenaCloud. +- Clone this repository to your local workspace. +- Using [Balena CLI](https://www.balena.io/docs/reference/cli/), push the code with `balena push ` +- See the magic happening, your device is getting updated 🌟Over-The-Air🌟! + + +## Configure the Gateway + +### Before configure your LoRa gateway + +The LoRa gateways are manufactured with a unique 64 bits (8 bytes) identifier, called EUI, which can be used to register the gateway on The Things Network. To get the EUI from your board it’s important to know the Ethernet MAC address of it. The TTN EUI will be the Ethernet mac address (6 bytes), which is unique, expanded with 2 more bytes (FFFE). This is a standard way to increment the MAC address from 6 to 8 bytes. + +To get the EUI, copy the TAG of the device which will be generated automatically when the device gets provisioned on balenaCloud. + +If that does not work, go to the terminal box and click "Select a target", then “HostOS”. Once you are inside the shell, type: + +```cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g' ``` + +Copy the result and you are ready to register your gateway with this EUI. + + +### Configure your The Things Network gateway + +1. Sign up at [The Things Network console](https://console.thethingsnetwork.org/). +2. Click Gateways button. +3. Click the "Register gateway" link. +4. Check “I’m using the legacy packet forwarder” checkbox. +5. Paste the EUI from the Ethernet mac address of the board (calculated above) +6. Complete the form and click Register gateway. + + +### Balena LoRa Basics Station Service Variables + +Once successfully registered, copy the The Things Network gateway KEY to configure your board variables on balenaCloud. + +1. Go to balenaCloud dashboard and get into your LoRa gateway device site. +2. Click "Device Variables" button on the left menu and add these variables. + +Most of the variables have been generated automatically when the Application has been created with the Deploy with Balena button. However it's important to introduce the `GW_ID`and `GW_KEY`from the The Things Network console. + + +Variable Name | Value | Description | Default +------------ | ------------- | ------------- | ------------- +**`GW_GPS`** | `STRING` | Enables GPS | true or false +**`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) +**`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) +**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 +**`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 20000000 +**`TC_URI`** | `STRING` | basics station TC URI to get connected | ```wss://lns.eu.thethings.network:443``` + + +At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. + + +## Attribution + +- This is an adaptation of the [Semtech Basics Station repository](https://github.com/lorabasics/basicstation). Documentation [here](https://doc.sm.tc/station). +- This is in part working thanks of the work of Jose Marcelino from RAK Wireless and Marc Pous from balena.io. +- This is in part based on excellent work done by the Balena.io Hardware Hackers team. diff --git a/README.md b/README.md index 78d8970e..7de6c54d 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,13 @@ RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station The example configuration connects to a public test server [s2.sm.tc](wss://s2.sm.tc) through which Station fetches all required credentials and a channel plan matching the region as determined from the IP address of the gateway. Provided there are active LoRa devices in proximity, received LoRa frames are printed in the log output on `stderr`. ## Instruction for Supported Platfroms +#### balena (Raspberry Pi 3/4 or balenaFin + RAK2245 or RAK831) + +Running this project is as simple as deploying it to a balenaCloud application. You can do it in just one click by using the button below: + +[![](https://www.balena.io/deploy.png)](https://dashboard.balena-cloud.com/deploy?repoUrl=https://github.com/balena-io-playground/basicstation) + +Follow instructions, click Add a Device and flash an SD card with that OS image dowloaded from balenaCloud. Enjoy the magic 🌟Over-The-Air🌟! #### Corecell Platform (Raspberry Pi as HOST + [SX1302CxxxxGW Concentrator](https://www.semtech.com/products/wireless-rf/lora-gateways/sx1302cxxxgw1)) @@ -164,3 +171,9 @@ Usage: station [OPTION...] Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options. ``` + + + + + + diff --git a/balena.yml b/balena.yml new file mode 100644 index 00000000..b2998dd5 --- /dev/null +++ b/balena.yml @@ -0,0 +1,6 @@ + +applicationEnvironmentVariables: + - GW_GPS: false + - GW_RESET_PIN: 11 + - SPI_SPEED: 20000000 + - TC_URI: wss://lns.eu.thethings.network:443 diff --git a/examples/live-s2.sm.tc/cups-boot.crt b/examples/live-s2.sm.tc/cups-boot.crt deleted file mode 100644 index 76b5420f..00000000 --- a/examples/live-s2.sm.tc/cups-boot.crt +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBkzCCATmgAwIBAgIBQTAKBggqhkjOPQQDAjBXMRAwDgYDVQQDDAdSb290IENB -MSAwHgYDVQQLDBdUcmFja0NlbnRyYWwgKGVpYVBvVWM5KTEUMBIGA1UECgwLVHJh -Y2tOZXQuaW8xCzAJBgNVBAYTAkNIMB4XDTE5MDMwNzE1MjgwNVoXDTIxMDMwNjE1 -MjgwNVowTzETMBEGA1UEAwwKZ3dwcm92LTo6MDEVMBMGA1UECwwMVHJhY2tDZW50 -cmFsMRQwEgYDVQQKDAtUcmFja05ldC5pbzELMAkGA1UEBhMCQ0gwWTATBgcqhkjO -PQIBBggqhkjOPQMBBwNCAASFyfmqBPkza9kd2IkrbU3zSRIriq5vOcgwfilctZVs -j8Z7XVBMdNLjriSjchVgyBTJfvMVMbvYTdzD7w5GBSNwMAoGCCqGSM49BAMCA0gA -MEUCIQCFGgSlP6GYM6uXd6KXuEwc098p5orHP/dxupGAZifquwIgbUh9UAR8tgAi -8TH36s9z+mz27ea7ezcmH8aM4W3Meng= ------END CERTIFICATE----- diff --git a/examples/live-s2.sm.tc/cups-boot.key b/examples/live-s2.sm.tc/cups-boot.key deleted file mode 100644 index 6c00c4e6..00000000 --- a/examples/live-s2.sm.tc/cups-boot.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIJbt0pUj24UIWS6HngUqJtP3uPpweSIqhB4TRoyHdzdqoAoGCCqGSM49 -AwEHoUQDQgAEhcn5qgT5M2vZHdiJK21N80kSK4qubznIMH4pXLWVbI/Ge11QTHTS -464ko3IVYMgUyX7zFTG72E3cw+8ORgUjcA== ------END EC PRIVATE KEY----- diff --git a/examples/live-s2.sm.tc/cups-boot.trust b/examples/live-s2.sm.tc/cups-boot.trust deleted file mode 100644 index 03178ecf..00000000 --- a/examples/live-s2.sm.tc/cups-boot.trust +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBlzCCATwCAQwwCgYIKoZIzj0EAwIwVzEQMA4GA1UEAwwHUm9vdCBDQTEgMB4G -A1UECwwXVHJhY2tDZW50cmFsIChlaWFQb1VjOSkxFDASBgNVBAoMC1RyYWNrTmV0 -LmlvMQswCQYDVQQGEwJDSDAeFw0xODExMDgxMjQyMDBaFw0yNDExMDYxMjQyMDBa -MFcxEDAOBgNVBAMMB1Jvb3QgQ0ExIDAeBgNVBAsMF1RyYWNrQ2VudHJhbCAoZWlh -UG9VYzkpMRQwEgYDVQQKDAtUcmFja05ldC5pbzELMAkGA1UEBhMCQ0gwWTATBgcq -hkjOPQIBBggqhkjOPQMBBwNCAAQpHfNq86xR2+pZY0dpurnn7IrkH9YaBoEGQ3K+ -ZXDYaR2PviPw8sbClqQG/pYEYsLpWNk9UeJtFv5oJtFXmgC9MAoGCCqGSM49BAMC -A0kAMEYCIQDQBlCSN+Bo+U2xnaPBE9RWUVjY9/95I64rilCRofn0kwIhAJZ3zlGc -yO4Wie3jJKKNCxOioaJZUdaJZUo14vkH9OFp ------END CERTIFICATE----- diff --git a/examples/live-s2.sm.tc/cups-boot.uri b/examples/live-s2.sm.tc/cups-boot.uri deleted file mode 100644 index bfa9fa97..00000000 --- a/examples/live-s2.sm.tc/cups-boot.uri +++ /dev/null @@ -1 +0,0 @@ -https://s2.sm.tc:7007 \ No newline at end of file diff --git a/examples/live-s2.sm.tc/makefile b/examples/live-s2.sm.tc/makefile index 80fce24f..c7634af7 100644 --- a/examples/live-s2.sm.tc/makefile +++ b/examples/live-s2.sm.tc/makefile @@ -39,6 +39,6 @@ kerlink: platform=kerlink variant=std make clean: - rm -rf cups.* cups-bak.* tc.* tc-bak.* station.log station.pid + rm -rf cups.* cups-bak.* tc-bak.* station.log station.pid .PHONY: all clean diff --git a/examples/live-s2.sm.tc/tc.trust b/examples/live-s2.sm.tc/tc.trust new file mode 100644 index 00000000..b2e43c93 --- /dev/null +++ b/examples/live-s2.sm.tc/tc.trust @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- diff --git a/examples/live-s2.sm.tc/tc.uri b/examples/live-s2.sm.tc/tc.uri new file mode 100644 index 00000000..351c5c87 --- /dev/null +++ b/examples/live-s2.sm.tc/tc.uri @@ -0,0 +1,2 @@ +wss://lns.eu.thethings.network:443 + diff --git a/setup.gmk b/setup.gmk index a123556f..58fbb1f3 100644 --- a/setup.gmk +++ b/setup.gmk @@ -35,18 +35,20 @@ NQ = $(if ${V},>/dev/null,) platform ?= linux variant ?= std +arch ?= default -include ${TD}/setup-${platform}.gmk LOCAL_ARCH := $(shell gcc -dumpmachine) -ARCH.linux = x86_64-linux-gnu -ARCH.linuxV2 = x86_64-linux-gnu -ARCH.linuxpico = x86_64-linux-gnu -ARCH.corecell = arm-linux-gnueabihf -ARCH.rpi = arm-linux-gnueabihf -ARCH.kerlink = arm-klk-linux-gnueabi -ARCH=${ARCH.${platform}} +ARCH.linux.default = x86_64-linux-gnu +ARCH.linuxV2.default = x86_64-linux-gnu +ARCH.linuxpico.default = x86_64-linux-gnu +ARCH.corecell.default = arm-linux-gnueabihf +ARCH.rpi.armv7hf = arm-linux-gnueabihf +ARCH.rpi.aarch64 = aarch64-linux-gnu +ARCH.kerlink.default = arm-klk-linux-gnueabi +ARCH=${ARCH.${platform}.${arch}} export TDfull := $(shell cd ${TD} && pwd) TOOLCHAIN=${HOME}/toolchain-${platform} diff --git a/start.sh b/start.sh new file mode 100644 index 00000000..0278622f --- /dev/null +++ b/start.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +TAG_KEY="EUI" +TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g') + +echo $TTN_EUI + +ID=$(curl -sX GET "https://api.balena-cloud.com/v5/device?\$filter=uuid%20eq%20'$BALENA_DEVICE_UUID'" \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer $BALENA_API_KEY" | \ +jq ".d | .[0] | .id") + +TAG=$(curl -sX POST \ +"https://api.balena-cloud.com/v5/device_tag" \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer $BALENA_API_KEY" \ +--data "{ \"device\": \"$ID\", \"tag_key\": \"$TAG_KEY\", \"value\": \"$TTN_EUI\" }" > /dev/null) + + +# declare map of hardware pins to GPIO on Raspberry Pi +declare -a pinToGPIO +pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) + + +cd examples/live-s2.sm.tc + +# Default to TTN server +TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} +TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} + + +GW_RESET_PIN=${GW_RESET_PIN:-11} +GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} + +# Setup TC files from environment +echo $TC_URI > tc.uri +echo "$TC_TRUST" > tc.trust + +# Reset gateway +echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" +echo $GW_RESET_GPIO > /sys/class/gpio/export +echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction +echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +echo $GW_RESET_GPIO > /sys/class/gpio/unexport + +RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station + From cb2ed21babd345babdc5feb291015a6efea24d12 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Mon, 13 Jul 2020 19:39:24 +0200 Subject: [PATCH 02/88] Update README with balena instructions --- README.md | 193 +++++++++++++++++------------------------------------- 1 file changed, 59 insertions(+), 134 deletions(-) diff --git a/README.md b/README.md index 7de6c54d..5fecaf36 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,34 @@ -[![Build Status](https://travis-ci.com/lorabasics/basicstation.svg?branch=master)](https://travis-ci.com/lorabasics/basicstation) +# LoRa Basics™ Station using balena.io and RAK2245 -# LoRa Basics™ Station +This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 Pi Hat. -[Basic Station](https://doc.sm.tc/station) is a LoRaWAN Gateway implementation, including features like -* **Ready for LoRaWAN Classes A, B, and C** -* **Unified Radio Abstraction Layer supporting Concentrator Reference Designs [v1.5](https://doc.sm.tc/station/gw_v1.5.html), [v2](https://doc.sm.tc/station/gw_v2.html) and [Corecell](https://doc.sm.tc/station/gw_corecell.html)** +## Introduction -* **Powerful Backend Protocols** (read [here](https://doc.sm.tc/station/tcproto.html) and [here](https://doc.sm.tc/station/cupsproto.html)) - - Centralized update and configuration management - - Centralized channel-plan management - - Centralized time synchronization and transfer - - Various authentication schemes (client certificate, auth tokens) - - Remote interactive shell +Deploy a The Things Network (TTN) LoRa gateway running the basics station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. -* **Lean Design** - - No external software dependencies (except mbedTLS and libloragw/-v2) - - Portable C code, no C++, dependent only on GNU libc - - Easily portable to Linux-based gateways and embedded systems - - No dependency on local time keeping - - No need for incoming connections +The Basics Station protocol enables the LoRa gateways with a reliable and secure communication between the gateways and the cloud and it is becoming the standard Packet Forward protocol used by most of the LoRaWAN operators. -## Documentation -The full documentation is available at [https://doc.sm.tc/station](https://doc.sm.tc/station). +## Getting started -### High Level Architecture +### Hardware -![High Level Station Architecture](https://doc.sm.tc/station/_images/architecture.png) +* Raspberry Pi 4 or [balenaFin](https://www.balena.io/fin/) +* [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) +* SD card in case of the RPi 4 -## Prerequisites +### Software -Building the Station binary from source, requires +* A TTN account ([sign up here](https://console.thethingsnetwork.org) +* A balenaCloud account ([sign up here](https://dashboard.balena-cloud.com/) +* [balenaEtcher](https://balena.io/etcher) -* gcc (C11 with GNU extensions) -* GNU make -* git -* bash +Once all of this is ready, you are able to deploy this repository following instructions below. -## First Steps +## Deploy the code -The following is a three-step quick start guide on how to build and run Station. It uses a Raspberry Pi as host platform and assumes a Concentrator Reference Design 1.5 compatible radio board connected via SPI. In this example the build process is done on the target platform itself (the make environment also supports cross compilation in which case the toolchain is expected in `~/toolchain-$platform` - see [setup.gmk](setup.gmk)). - -#### Step 1: Cloning the Station Repository - -``` sourceCode -git clone https://github.com/lorabasics/basicstation.git -``` - -#### Step 2: Compiling the Station Binary - -``` sourceCode -cd basicstation -make platform=rpi variant=std -``` - -The build process consists of the following steps: - -* Fetch and build dependencies, namely [mbedTLS](https://github.com/ARMmbed/mbedtls) and [libloragw](https://github.com/Lora-net/lora_gateway) -* Setup build environment within subdirectory `build-$platform-$variant/` -* Compile station source files into executable `build-$platform-$variant/bin/station` - -#### Step 3: Running the Example Configuration on a Raspberry Pi - -``` sourceCode -cd examples/live-s2.sm.tc -RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station -``` - -**Note:** The SPI device for the radio MAY be passed as an environment variable using `RADIODEV`. - -The example configuration connects to a public test server [s2.sm.tc](wss://s2.sm.tc) through which Station fetches all required credentials and a channel plan matching the region as determined from the IP address of the gateway. Provided there are active LoRa devices in proximity, received LoRa frames are printed in the log output on `stderr`. - -## Instruction for Supported Platfroms -#### balena (Raspberry Pi 3/4 or balenaFin + RAK2245 or RAK831) +### Via [Balena Deploy](https://www.balena.io/docs/learn/deploy/deploy-with-balena-button/) Running this project is as simple as deploying it to a balenaCloud application. You can do it in just one click by using the button below: @@ -81,99 +36,69 @@ Running this project is as simple as deploying it to a balenaCloud application. Follow instructions, click Add a Device and flash an SD card with that OS image dowloaded from balenaCloud. Enjoy the magic 🌟Over-The-Air🌟! -#### Corecell Platform (Raspberry Pi as HOST + [SX1302CxxxxGW Concentrator](https://www.semtech.com/products/wireless-rf/lora-gateways/sx1302cxxxgw1)) -##### Compile and Running the Example +### Via [Balena-Cli](https://www.balena.io/docs/reference/balena-cli/) + +If you are a balena CLI expert, feel free to use balena CLI. + +- Sign up on [balena.io](https://dashboard.balena.io/signup) +- Create a new application on balenaCloud. +- Clone this repository to your local workspace. +- Using [Balena CLI](https://www.balena.io/docs/reference/cli/), push the code with `balena push ` +- See the magic happening, your device is getting updated 🌟Over-The-Air🌟! + -``` sourceCode -cd basicstation -make platform=corecell variant=std -cd examples/corecell -./start-station.sh -l ./lns-ttn -``` +## Configure the Gateway -This example configuration for Corecell connects to [The Things Network](https://www.thethingsnetwork.org/) public LNS. The example [station.conf](station.conf) file holds the required radio configurations and station fetches the channel plan from the configured LNS url ([tc.uri](tc.uri)). +### Before configure your LoRa gateway -#### PicoCell Gateway (Linux OS as HOST + [SX1308 USB Reference design](https://www.semtech.com/products/wireless-rf/lora-gateways/sx1308p868gw)) +The LoRa gateways are manufactured with a unique 64 bits (8 bytes) identifier, called EUI, which can be used to register the gateway on The Things Network. To get the EUI from your board it’s important to know the Ethernet MAC address of it. The TTN EUI will be the Ethernet mac address (6 bytes), which is unique, expanded with 2 more bytes (FFFE). This is a standard way to increment the MAC address from 6 to 8 bytes. +To get the EUI, copy the TAG of the device which will be generated automatically when the device gets provisioned on balenaCloud. -##### Compile and Running the Example +If that does not work, go to the terminal box and click "Select a target", then “HostOS”. Once you are inside the shell, type: -``` sourceCode -cd basicstation -make platform=linuxpico variant=std -cd examples/live-s2.sm.tc -RADIODEV=/dev/ttyACM0 ../../build-linuxpico-std/bin/station -``` +```cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g' ``` -**Note:** The serial device for the PicoCell MAY be passed as an environment variable using `RADIODEV`. +Copy the result and you are ready to register your gateway with this EUI. -## Next Steps -Next, +### Configure your The Things Network gateway -* consult the help menu of Station via `station --help`, -* inspect the `station.conf` and `cups-boot.*` [example configuration files](/examples/live-s2.sm.tc), -* tune your local [configuration](https://doc.sm.tc/station/conf.html), -* learn how to [compile Station](https://doc.sm.tc/station/compile.html) for your target platform. +1. Sign up at [The Things Network console](https://console.thethingsnetwork.org/). +2. Click Gateways button. +3. Click the "Register gateway" link. +4. Check “I’m using the legacy packet forwarder” checkbox. +5. Paste the EUI from the Ethernet mac address of the board (calculated above) +6. Complete the form and click Register gateway. -Check out the other examples: -* [Simulation Example](/examples/simulation) - An introduction to the simulation environment. -* [CUPS Example](/examples/cups) - Demonstration of the CUPS protocol within the simulation environment. -* [Station to Pkfwd Protocol Bridge Example](/examples/station2pkfwd) - Connect Basic Station to LNS supporting the legacy protocol. +### Balena LoRa Basics Station Service Variables -## Usage +Once successfully registered, copy the The Things Network gateway KEY to configure your board variables on balenaCloud. -The Station binary accepts the following command-line options: +1. Go to balenaCloud dashboard and get into your LoRa gateway device site. +2. Click "Device Variables" button on the left menu and add these variables. -``` -Usage: station [OPTION...] +Most of the variables have been generated automatically when the Application has been created with the Deploy with Balena button. However it's important to introduce the `GW_ID`and `GW_KEY`from the The Things Network console. - -d, --daemon First check if another process is still alive. If - so do nothing and exit. Otherwise fork a worker - process to operate the radios and network - protocols. If the subprocess died respawn it with - an appropriate back off. - -f, --force If a station process is already running, kill it - before continuing with requested operation mode. - -h, --home=DIR Home directory for configuration files. Default is - the current working directory. Overrides - environment STATION_DIR. - -i, --radio-init=cmd Program/script to run before reinitializing radio - hardware. By default nothing is being executed. - Overrides environment STATION_RADIOINIT. - -k, --kill Kill a currently running station process. - -l, --log-level=LVL|0..7 Set a log level LVL=#loglvls# or use a numeric - value. Overrides environment STATION_LOGLEVEL. - -L, --log-file=FILE[,SIZE[,ROT]] - Write log entries to FILE. If FILE is '-' then - write to stderr. Optionally followed by a max file - SIZE and a number of rotation files. If ROT is 0 - then keep only FILE. If ROT is 1 then keep one - more old log file around. Overrides environment - STATION_LOGFILE. - -N, --no-tc Do not connect to a LNS. Only run CUPS - functionality. - -p, --params Print current parameter settings. - -t, --temp=DIR Temp directory for frequently written files. - Default is /tmp. Overrides environment - STATION_TEMPDIR. - -x, --eui-prefix=id6 Turn MAC address into EUI by adding this prefix. - If the argument has value ff:fe00:0 then the EUI - is formed by inserting FFFE in the middle. If - absent use MAC or routerid as is. Overrides - environment STATION_EUIPREFIX. - -?, --help Give this help list - --usage Give a short usage message - -v, --version Print station version. -Mandatory or optional arguments to long options are also mandatory or optional -for any corresponding short options. -``` +Variable Name | Value | Description | Default +------------ | ------------- | ------------- | ------------- +**`GW_GPS`** | `STRING` | Enables GPS | true or false +**`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) +**`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) +**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 +**`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 20000000 +**`TC_URI`** | `STRING` | basics station TC URI to get connected | ```wss://lns.eu.thethings.network:443``` +At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. +## Attribution +- This is an adaptation of the [Semtech Basics Station repository](https://github.com/lorabasics/basicstation). Documentation [here](https://doc.sm.tc/station). +- This is in part working thanks of the work of Jose Marcelino from RAK Wireless and Marc Pous from balena.io. +- This is in part based on excellent work done by the Balena.io Hardware Hackers team. From f18d6713fcb7a5f1d8dcd6f672511c1c8b17ea2d Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Mon, 13 Jul 2020 20:59:22 +0200 Subject: [PATCH 03/88] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5fecaf36..eab60aef 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ The Basics Station protocol enables the LoRa gateways with a reliable and secure ### Software -* A TTN account ([sign up here](https://console.thethingsnetwork.org) -* A balenaCloud account ([sign up here](https://dashboard.balena-cloud.com/) +* A TTN account ([sign up here](https://console.thethingsnetwork.org)) +* A balenaCloud account ([sign up here](https://dashboard.balena-cloud.com/)) * [balenaEtcher](https://balena.io/etcher) Once all of this is ready, you are able to deploy this repository following instructions below. @@ -32,7 +32,7 @@ Once all of this is ready, you are able to deploy this repository following inst Running this project is as simple as deploying it to a balenaCloud application. You can do it in just one click by using the button below: -[![](https://www.balena.io/deploy.png)](https://dashboard.balena-cloud.com/deploy?repoUrl=https://github.com/balena-io-playground/basicstation) +[![](https://www.balena.io/deploy.png)](https://dashboard.balena-cloud.com/deploy?repoUrl=https://github.com/balenalabs/basicstation) Follow instructions, click Add a Device and flash an SD card with that OS image dowloaded from balenaCloud. Enjoy the magic 🌟Over-The-Air🌟! From 16b2d0eff2f0c7edd4976742c3de324f2a433fc2 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 16 Jul 2020 15:10:48 +0200 Subject: [PATCH 04/88] Update README with US TC_URI example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eab60aef..63713b0d 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Variable Name | Value | Description | Default **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 20000000 -**`TC_URI`** | `STRING` | basics station TC URI to get connected | ```wss://lns.eu.thethings.network:443``` +**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in US region use ```wss://lns.us.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. From cf7cf2c06d06eb57a655a0368798c34297e0cefe Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 16 Jul 2020 15:14:23 +0200 Subject: [PATCH 05/88] Update multi-regions TC_URI --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 63713b0d..a8948aac 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,9 @@ Once successfully registered, copy the The Things Network gateway KEY to configu 1. Go to balenaCloud dashboard and get into your LoRa gateway device site. 2. Click "Device Variables" button on the left menu and add these variables. -Most of the variables have been generated automatically when the Application has been created with the Deploy with Balena button. However it's important to introduce the `GW_ID`and `GW_KEY`from the The Things Network console. +Most of the variables have been generated automatically when the Application has been created with the Deploy with Balena button. Before starting check the region where you are going to deploy the gateway, de facto configuration is for EU gateways. Change the ```TC_URI```if you are in a different zone than European. + +And it's important to introduce the `GW_ID`and `GW_KEY`from the The Things Network console. Variable Name | Value | Description | Default @@ -90,7 +92,7 @@ Variable Name | Value | Description | Default **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 20000000 -**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in US region use ```wss://lns.us.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` +**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu|us|in|au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. From 4c627bd6f7b0c9b193016ce3cdbf53c398d1c90e Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 16 Jul 2020 15:18:55 +0200 Subject: [PATCH 06/88] Update multi-region TC_URI --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8948aac..cd306bf2 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Variable Name | Value | Description | Default **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 20000000 -**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu|us|in|au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` +**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. From 874553a298148c9061f3e2d9af810cec069d1588 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Mon, 27 Jul 2020 15:03:06 +0200 Subject: [PATCH 07/88] Update SPI SPEED Updated the SPI SPEED to 2Mhz (there was an extra zero) --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index b2998dd5..ccd337cd 100644 --- a/balena.yml +++ b/balena.yml @@ -2,5 +2,5 @@ applicationEnvironmentVariables: - GW_GPS: false - GW_RESET_PIN: 11 - - SPI_SPEED: 20000000 + - SPI_SPEED: 2000000 - TC_URI: wss://lns.eu.thethings.network:443 From d232fd2617e3aa8c582043cc3e421aaa4c2cf461 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Mon, 27 Jul 2020 15:03:45 +0200 Subject: [PATCH 08/88] Updated SPI SPEED Updated the SPI SPEED to 2Mhz (it has an extra zero) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd306bf2..5dc2560c 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Variable Name | Value | Description | Default **`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 -**`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 20000000 +**`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 2000000 **`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` From cc7e0cdee3e475166df9cfe3a43e2feb63d6d727 Mon Sep 17 00:00:00 2001 From: Jose Marcelino Date: Tue, 25 Aug 2020 19:50:37 +0100 Subject: [PATCH 09/88] Fix SPI speed to 2Mhz --- deps/lgw/v5.0.1-linux.patch | 3 ++- deps/lgw/v5.0.1-rpi.patch | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/deps/lgw/v5.0.1-linux.patch b/deps/lgw/v5.0.1-linux.patch index 8a2281b6..7d80091d 100644 --- a/deps/lgw/v5.0.1-linux.patch +++ b/deps/lgw/v5.0.1-linux.patch @@ -125,7 +125,8 @@ index c01ed1c..0e2b64c 100644 @@ -54,7 +54,7 @@ Maintainer: Sylvain Miermont #define READ_ACCESS 0x00 #define WRITE_ACCESS 0x80 - #define SPI_SPEED 8000000 +-#define SPI_SPEED 8000000 ++#define SPI_SPEED 2000000 -#define SPI_DEV_PATH "/dev/spidev0.0" +#define SPI_DEV_PATH (getenv("LORAGW_SPI")==NULL ? "/dev/spidev0.0" : getenv("LORAGW_SPI")) //#define SPI_DEV_PATH "/dev/spidev32766.0" diff --git a/deps/lgw/v5.0.1-rpi.patch b/deps/lgw/v5.0.1-rpi.patch index 8a2281b6..7d80091d 100644 --- a/deps/lgw/v5.0.1-rpi.patch +++ b/deps/lgw/v5.0.1-rpi.patch @@ -125,7 +125,8 @@ index c01ed1c..0e2b64c 100644 @@ -54,7 +54,7 @@ Maintainer: Sylvain Miermont #define READ_ACCESS 0x00 #define WRITE_ACCESS 0x80 - #define SPI_SPEED 8000000 +-#define SPI_SPEED 8000000 ++#define SPI_SPEED 2000000 -#define SPI_DEV_PATH "/dev/spidev0.0" +#define SPI_DEV_PATH (getenv("LORAGW_SPI")==NULL ? "/dev/spidev0.0" : getenv("LORAGW_SPI")) //#define SPI_DEV_PATH "/dev/spidev32766.0" From 6aa191791686f279ffb13a907a7bd29827f13401 Mon Sep 17 00:00:00 2001 From: mpous Date: Fri, 18 Sep 2020 17:05:36 +0200 Subject: [PATCH 10/88] Corecell build --- Dockerfile.template | 3 ++- setup.gmk | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile.template b/Dockerfile.template index 3d3f8f7c..c3cfbd0d 100644 --- a/Dockerfile.template +++ b/Dockerfile.template @@ -15,7 +15,8 @@ WORKDIR /usr/src/app COPY . . # Compile our source code -RUN make platform=rpi variant=std arch=%%BALENA_ARCH%% +#RUN make platform=rpi variant=std arch=%%BALENA_ARCH%% +RUN make platform=corecell variant=std arch=%%BALENA_ARCH%% # Launch our binary on container startup. CMD ["bash", "start.sh"] diff --git a/setup.gmk b/setup.gmk index 58fbb1f3..8a05246c 100644 --- a/setup.gmk +++ b/setup.gmk @@ -45,6 +45,7 @@ ARCH.linux.default = x86_64-linux-gnu ARCH.linuxV2.default = x86_64-linux-gnu ARCH.linuxpico.default = x86_64-linux-gnu ARCH.corecell.default = arm-linux-gnueabihf +ARCH.corecell.aarch64 = aarch64-linux-gnu ARCH.rpi.armv7hf = arm-linux-gnueabihf ARCH.rpi.aarch64 = aarch64-linux-gnu ARCH.kerlink.default = arm-klk-linux-gnueabi From 6c604c37aaf878f462dfd2bb60ed6b417ce67dd3 Mon Sep 17 00:00:00 2001 From: mpous Date: Fri, 18 Sep 2020 20:02:58 +0200 Subject: [PATCH 11/88] More changes corecell --- examples/corecell/reset_lgw.sh | 13 +++++++------ start.sh | 13 ++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/corecell/reset_lgw.sh b/examples/corecell/reset_lgw.sh index 0136d72e..2332e055 100755 --- a/examples/corecell/reset_lgw.sh +++ b/examples/corecell/reset_lgw.sh @@ -21,16 +21,17 @@ WAIT_GPIO() { init() { # setup GPIOs echo "$SX1302_RESET_PIN" > /sys/class/gpio/export; WAIT_GPIO - echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/export; WAIT_GPIO + #echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/export; WAIT_GPIO # set GPIOs as output echo "out" > /sys/class/gpio/gpio$SX1302_RESET_PIN/direction; WAIT_GPIO - echo "out" > /sys/class/gpio/gpio$SX1302_POWER_EN_PIN/direction; WAIT_GPIO + #echo "out" > /sys/class/gpio/gpio$SX1302_POWER_EN_PIN/direction; WAIT_GPIO } reset() { echo "CoreCell reset through GPIO$SX1302_RESET_PIN..." echo "CoreCell power enable through GPIO$SX1302_POWER_EN_PIN..." + echo "SX1302 reset through GPIO$SX1302_RESET_PIN..." # write output for SX1302 CoreCell power_enable and reset echo "1" > /sys/class/gpio/gpio$SX1302_POWER_EN_PIN/value; WAIT_GPIO @@ -45,10 +46,10 @@ term() { then echo "$SX1302_RESET_PIN" > /sys/class/gpio/unexport; WAIT_GPIO fi - if [ -d /sys/class/gpio/gpio$SX1302_POWER_EN_PIN ] - then - echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/unexport; WAIT_GPIO - fi + #if [ -d /sys/class/gpio/gpio$SX1302_POWER_EN_PIN ] + #then + # echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/unexport; WAIT_GPIO + #fi } case "$1" in diff --git a/start.sh b/start.sh index 0278622f..c6bf68ca 100644 --- a/start.sh +++ b/start.sh @@ -22,19 +22,19 @@ declare -a pinToGPIO pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) -cd examples/live-s2.sm.tc +cd examples/corecell # Default to TTN server TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} +TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)} -GW_RESET_PIN=${GW_RESET_PIN:-11} +GW_RESET_PIN=${GW_RESET_PIN:-22} GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} # Setup TC files from environment -echo $TC_URI > tc.uri -echo "$TC_TRUST" > tc.trust +echo $TC_URI > ./lns-ttn/tc.uri +echo "$TC_TRUST" > ./lns-ttn/tc.trust # Reset gateway echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" @@ -45,5 +45,4 @@ echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value echo $GW_RESET_GPIO > /sys/class/gpio/unexport -RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station - +./start-station.sh -l ./lns-ttn From c3e6d96392bbe9ecbef5e1c2fecfc260962b5a66 Mon Sep 17 00:00:00 2001 From: mpous Date: Mon, 21 Sep 2020 22:06:05 +0200 Subject: [PATCH 12/88] the corecell way --- Dockerfile.template | 2 +- examples/corecell/reset_lgw.sh | 19 ++++++------ examples/corecell/start-station.sh | 1 - start-corecell.sh | 47 ++++++++++++++++++++++++++++++ start.sh | 15 +++++----- 5 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 start-corecell.sh diff --git a/Dockerfile.template b/Dockerfile.template index c3cfbd0d..65b0740d 100644 --- a/Dockerfile.template +++ b/Dockerfile.template @@ -19,4 +19,4 @@ COPY . . RUN make platform=corecell variant=std arch=%%BALENA_ARCH%% # Launch our binary on container startup. -CMD ["bash", "start.sh"] +CMD ["bash", "start-corecell.sh"] diff --git a/examples/corecell/reset_lgw.sh b/examples/corecell/reset_lgw.sh index 2332e055..d8c9c591 100755 --- a/examples/corecell/reset_lgw.sh +++ b/examples/corecell/reset_lgw.sh @@ -11,7 +11,7 @@ # GPIO mapping has to be adapted with HW # -SX1302_RESET_PIN=23 +SX1302_RESET_PIN=17 SX1302_POWER_EN_PIN=18 WAIT_GPIO() { @@ -21,17 +21,16 @@ WAIT_GPIO() { init() { # setup GPIOs echo "$SX1302_RESET_PIN" > /sys/class/gpio/export; WAIT_GPIO - #echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/export; WAIT_GPIO + echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/export; WAIT_GPIO # set GPIOs as output echo "out" > /sys/class/gpio/gpio$SX1302_RESET_PIN/direction; WAIT_GPIO - #echo "out" > /sys/class/gpio/gpio$SX1302_POWER_EN_PIN/direction; WAIT_GPIO + echo "out" > /sys/class/gpio/gpio$SX1302_POWER_EN_PIN/direction; WAIT_GPIO } reset() { - echo "CoreCell reset through GPIO$SX1302_RESET_PIN..." - echo "CoreCell power enable through GPIO$SX1302_POWER_EN_PIN..." - echo "SX1302 reset through GPIO$SX1302_RESET_PIN..." + echo "RAK2287 reset through GPIO$SX1302_RESET_PIN..." + echo "RAK2287 power enable through GPIO$SX1302_POWER_EN_PIN..." # write output for SX1302 CoreCell power_enable and reset echo "1" > /sys/class/gpio/gpio$SX1302_POWER_EN_PIN/value; WAIT_GPIO @@ -46,10 +45,10 @@ term() { then echo "$SX1302_RESET_PIN" > /sys/class/gpio/unexport; WAIT_GPIO fi - #if [ -d /sys/class/gpio/gpio$SX1302_POWER_EN_PIN ] - #then - # echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/unexport; WAIT_GPIO - #fi + if [ -d /sys/class/gpio/gpio$SX1302_POWER_EN_PIN ] + then + echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/unexport; WAIT_GPIO + fi } case "$1" in diff --git a/examples/corecell/start-station.sh b/examples/corecell/start-station.sh index 5317c199..dc28d0ff 100755 --- a/examples/corecell/start-station.sh +++ b/examples/corecell/start-station.sh @@ -78,7 +78,6 @@ fi STATION_BIN="../../build-corecell-$variant/bin/station" - if [ -f "$STATION_BIN" ]; then printf "Using variant=$variant, lns_config='$lns_config'\n" printf "$GREEN Starting Station ... $NC\n" diff --git a/start-corecell.sh b/start-corecell.sh new file mode 100644 index 00000000..92cb6322 --- /dev/null +++ b/start-corecell.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +TAG_KEY="EUI" +TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g') + +echo $TTN_EUI + +ID=$(curl -sX GET "https://api.balena-cloud.com/v5/device?\$filter=uuid%20eq%20'$BALENA_DEVICE_UUID'" \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer $BALENA_API_KEY" | \ +jq ".d | .[0] | .id") + +TAG=$(curl -sX POST \ +"https://api.balena-cloud.com/v5/device_tag" \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer $BALENA_API_KEY" \ +--data "{ \"device\": \"$ID\", \"tag_key\": \"$TAG_KEY\", \"value\": \"$TTN_EUI\" }" > /dev/null) + + +# declare map of hardware pins to GPIO on Raspberry Pi +declare -a pinToGPIO +pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) + +cd examples/corecell + +# Default to TTN server +TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} +TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)} + + +GW_RESET_PIN=${GW_RESET_PIN:-22} +GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} + +# Setup TC files from environment +echo $TC_URI > ./lns-ttn/tc.uri +echo "$TC_TRUST" > ./lns-ttn/tc.trust + +# Reset gateway +#echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" +#echo $GW_RESET_GPIO > /sys/class/gpio/export +#echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction +#echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +#echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +#echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +#echo $GW_RESET_GPIO > /sys/class/gpio/unexport + +./start-station.sh -l ./lns-ttn diff --git a/start.sh b/start.sh index c6bf68ca..92cb6322 100644 --- a/start.sh +++ b/start.sh @@ -21,7 +21,6 @@ TAG=$(curl -sX POST \ declare -a pinToGPIO pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) - cd examples/corecell # Default to TTN server @@ -37,12 +36,12 @@ echo $TC_URI > ./lns-ttn/tc.uri echo "$TC_TRUST" > ./lns-ttn/tc.trust # Reset gateway -echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" -echo $GW_RESET_GPIO > /sys/class/gpio/export -echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction -echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -echo $GW_RESET_GPIO > /sys/class/gpio/unexport +#echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" +#echo $GW_RESET_GPIO > /sys/class/gpio/export +#echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction +#echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +#echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +#echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +#echo $GW_RESET_GPIO > /sys/class/gpio/unexport ./start-station.sh -l ./lns-ttn From 4d8c4c1fe015ec9ea6c10fe3e9ab3e44a0b9646e Mon Sep 17 00:00:00 2001 From: mpous Date: Mon, 21 Sep 2020 22:20:23 +0200 Subject: [PATCH 13/88] Corecell last changes --- README.md | 9 +++++---- examples/corecell/lns-ttn/station.conf | 3 +-- start-corecell.sh | 3 ++- start.sh | 8 +++++--- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5dc2560c..738569cb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# LoRa Basics™ Station using balena.io and RAK2245 +# LoRa Basics™ Station using balena.io and RAK2287 -This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 Pi Hat. +This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2287 concentrator with a Pi Hat. ## Introduction @@ -15,7 +15,8 @@ The Basics Station protocol enables the LoRa gateways with a reliable and secure ### Hardware * Raspberry Pi 4 or [balenaFin](https://www.balena.io/fin/) -* [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) +* [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) +* [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) * SD card in case of the RPi 4 ### Software @@ -91,7 +92,7 @@ Variable Name | Value | Description | Default **`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 -**`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 2000000 +**`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2287 uses SPI to communicate and needs to use a specific speed | 2000000 **`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` diff --git a/examples/corecell/lns-ttn/station.conf b/examples/corecell/lns-ttn/station.conf index 4618940f..ceaf9b26 100644 --- a/examples/corecell/lns-ttn/station.conf +++ b/examples/corecell/lns-ttn/station.conf @@ -49,5 +49,4 @@ "log_size": 10000000, "log_rotate": 3 } -} - +} \ No newline at end of file diff --git a/start-corecell.sh b/start-corecell.sh index 92cb6322..b3a23ac3 100644 --- a/start-corecell.sh +++ b/start-corecell.sh @@ -25,7 +25,8 @@ cd examples/corecell # Default to TTN server TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)} +#TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)} +TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} GW_RESET_PIN=${GW_RESET_PIN:-22} diff --git a/start.sh b/start.sh index 92cb6322..02e1f580 100644 --- a/start.sh +++ b/start.sh @@ -21,12 +21,12 @@ TAG=$(curl -sX POST \ declare -a pinToGPIO pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) -cd examples/corecell + +cd examples/live-s2.sm.tc # Default to TTN server TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)} - +TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} GW_RESET_PIN=${GW_RESET_PIN:-22} GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} @@ -44,4 +44,6 @@ echo "$TC_TRUST" > ./lns-ttn/tc.trust #echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value #echo $GW_RESET_GPIO > /sys/class/gpio/unexport +#RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station ./start-station.sh -l ./lns-ttn + From 3436e0d52badf4ca23ddc4c970466284b1b4b6cb Mon Sep 17 00:00:00 2001 From: mpous Date: Mon, 21 Sep 2020 22:24:19 +0200 Subject: [PATCH 14/88] Corecell last changes --- start-corecell.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/start-corecell.sh b/start-corecell.sh index b3a23ac3..92cb6322 100644 --- a/start-corecell.sh +++ b/start-corecell.sh @@ -25,8 +25,7 @@ cd examples/corecell # Default to TTN server TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -#TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)} -TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} +TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)} GW_RESET_PIN=${GW_RESET_PIN:-22} From dba36b1522008b135f9f92de4117c7fc7027bf75 Mon Sep 17 00:00:00 2001 From: mpous Date: Mon, 21 Sep 2020 22:31:27 +0200 Subject: [PATCH 15/88] Corecell last changes --- deps/lgw1302/V1.0.5-corecell.patch | 390 +++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) diff --git a/deps/lgw1302/V1.0.5-corecell.patch b/deps/lgw1302/V1.0.5-corecell.patch index 27caa24c..1a9df99e 100644 --- a/deps/lgw1302/V1.0.5-corecell.patch +++ b/deps/lgw1302/V1.0.5-corecell.patch @@ -298,3 +298,393 @@ index 77c3d4d..487283f 100644 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int timestamp_counter_mode(bool enable_precision_ts, uint8_t max_ts_metrics, uint8_t nb_symbols) { +diff --git a/libloragw/Makefile b/libloragw/Makefile +index 262167a..439b23a 100644 +--- a/libloragw/Makefile ++++ b/libloragw/Makefile +@@ -85,7 +85,7 @@ $(OBJDIR)/%.o: src/%.c $(INCLUDES) inc/config.h | $(OBJDIR) + + ### static library + +-libloragw.a: $(OBJDIR)/loragw_spi.o $(OBJDIR)/loragw_i2c.o $(OBJDIR)/loragw_aux.o $(OBJDIR)/loragw_reg.o $(OBJDIR)/loragw_sx1250.o $(OBJDIR)/loragw_sx125x.o $(OBJDIR)/loragw_sx1302.o $(OBJDIR)/loragw_cal.o $(OBJDIR)/loragw_debug.o $(OBJDIR)/loragw_hal.o $(OBJDIR)/loragw_stts751.o $(OBJDIR)/loragw_gps.o $(OBJDIR)/loragw_sx1302_timestamp.o $(OBJDIR)/loragw_sx1302_rx.o ++libloragw.a: $(OBJDIR)/loragw_spi.o $(OBJDIR)/loragw_i2c.o $(OBJDIR)/loragw_aux.o $(OBJDIR)/loragw_reg.o $(OBJDIR)/loragw_sx1250.o $(OBJDIR)/loragw_sx125x.o $(OBJDIR)/loragw_sx1302.o $(OBJDIR)/loragw_cal.o $(OBJDIR)/loragw_debug.o $(OBJDIR)/loragw_hal.o $(OBJDIR)/loragw_gps.o $(OBJDIR)/loragw_sx1302_timestamp.o $(OBJDIR)/loragw_sx1302_rx.o + $(AR) rcs $@ $^ + + ### test programs +diff --git a/libloragw/inc/loragw_stts751.h b/libloragw/inc/loragw_stts751.h +deleted file mode 100644 +index b1a898a..0000000 +--- a/libloragw/inc/loragw_stts751.h ++++ /dev/null +@@ -1,58 +0,0 @@ +-/* +- / _____) _ | | +-( (____ _____ ____ _| |_ _____ ____| |__ +- \____ \| ___ | (_ _) ___ |/ ___) _ \ +- _____) ) ____| | | || |_| ____( (___| | | | +-(______/|_____)_|_|_| \__)_____)\____)_| |_| +- (C)2019 Semtech +- +-Description: +- Basic driver for ST ts751 temperature sensor +- +-License: Revised BSD License, see LICENSE.TXT file include in the project +-*/ +- +- +-#ifndef _LORAGW_STTS751_H +-#define _LORAGW_STTS751_H +- +-/* -------------------------------------------------------------------------- */ +-/* --- DEPENDANCIES --------------------------------------------------------- */ +- +-#include /* C99 types */ +-#include /* bool type */ +- +-#include "config.h" /* library configuration options (dynamically generated) */ +- +-/* -------------------------------------------------------------------------- */ +-/* --- INTERNAL SHARED TYPES ------------------------------------------------ */ +- +-/* -------------------------------------------------------------------------- */ +-/* --- INTERNAL SHARED FUNCTIONS -------------------------------------------- */ +- +-/* -------------------------------------------------------------------------- */ +-/* --- PUBLIC CONSTANTS ----------------------------------------------------- */ +- +-#define I2C_PORT_TEMP_SENSOR_0 0x39 /* STTS751-0DP3F */ +-#define I2C_PORT_TEMP_SENSOR_1 0x3B /* STTS751-1DP3F */ +- +-/* -------------------------------------------------------------------------- */ +-/* --- PUBLIC FUNCTIONS ----------------------------------------------------- */ +- +-/** +-@brief TODO +-@param TODO +-@return TODO +-*/ +-int stts751_configure(int i2c_fd, uint8_t i2c_addr); +- +-/** +-@brief TODO +-@param TODO +-@return TODO +-*/ +-int stts751_get_temperature(int i2c_fd, uint8_t i2c_addr, float * temperature); +- +-#endif +- +-/* --- EOF ------------------------------------------------------------------ */ +diff --git a/libloragw/src/loragw_hal.c b/libloragw/src/loragw_hal.c +index 3b00c09..66d5c97 100644 +--- a/libloragw/src/loragw_hal.c ++++ b/libloragw/src/loragw_hal.c +@@ -41,7 +41,7 @@ License: Revised BSD License, see LICENSE.TXT file include in the project + #include "loragw_sx1250.h" + #include "loragw_sx125x.h" + #include "loragw_sx1302.h" +-#include "loragw_stts751.h" ++ + #include "loragw_debug.h" + + /* -------------------------------------------------------------------------- */ +@@ -181,8 +181,8 @@ static lgw_context_t lgw_context = { + FILE * log_file = NULL; + + /* I2C temperature sensor handles */ +-static int ts_fd = -1; +-static uint8_t ts_addr = 0xFF; ++//static int ts_fd = -1; ++//static uint8_t ts_addr = 0xFF; + + /* -------------------------------------------------------------------------- */ + /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ +@@ -719,22 +719,23 @@ int lgw_start(void) { + dbg_init_gpio(); + #endif + ++// + /* Try to configure temperature sensor STTS751-0DP3F */ +- ts_addr = I2C_PORT_TEMP_SENSOR_0; +- i2c_linuxdev_open(I2C_DEVICE, ts_addr, &ts_fd); +- err = stts751_configure(ts_fd, ts_addr); +- if (err != LGW_I2C_SUCCESS) { +- i2c_linuxdev_close(ts_fd); +- ts_fd = -1; +- /* Not found, try to configure temperature sensor STTS751-1DP3F */ +- ts_addr = I2C_PORT_TEMP_SENSOR_1; +- i2c_linuxdev_open(I2C_DEVICE, ts_addr, &ts_fd); +- err = stts751_configure(ts_fd, ts_addr); +- if (err != LGW_I2C_SUCCESS) { +- printf("ERROR: failed to configure the temperature sensor\n"); +- return LGW_HAL_ERROR; +- } +- } ++// ts_addr = I2C_PORT_TEMP_SENSOR_0; ++// i2c_linuxdev_open(I2C_DEVICE, ts_addr, &ts_fd); ++// err = stts751_configure(ts_fd, ts_addr); ++// if (err != LGW_I2C_SUCCESS) { ++// i2c_linuxdev_close(ts_fd); ++// ts_fd = -1; ++// /* Not found, try to configure temperature sensor STTS751-1DP3F */ ++// ts_addr = I2C_PORT_TEMP_SENSOR_1; ++// i2c_linuxdev_open(I2C_DEVICE, ts_addr, &ts_fd); ++// err = stts751_configure(ts_fd, ts_addr); ++// if (err != LGW_I2C_SUCCESS) { ++// printf("ERROR: failed to configure the temperature sensor\n"); ++// return LGW_HAL_ERROR; ++// } ++// } + + /* set hal state */ + CONTEXT_STARTED = true; +@@ -762,10 +763,10 @@ int lgw_stop(void) { + lgw_disconnect(); + + DEBUG_MSG("INFO: Closing I2C\n"); +- err = i2c_linuxdev_close(ts_fd); +- if (err != 0) { +- printf("ERROR: failed to close I2C device (err=%i)\n", err); +- } ++ //err = i2c_linuxdev_close(ts_fd); ++ //if (err != 0) { ++ // printf("ERROR: failed to close I2C device (err=%i)\n", err); ++ //} + + CONTEXT_STARTED = false; + return LGW_HAL_SUCCESS; +@@ -778,7 +779,9 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { + uint8_t nb_pkt_fetched = 0; + uint16_t nb_pkt_found = 0; + uint16_t nb_pkt_left = 0; +- float current_temperature, rssi_temperature_offset; ++ //float current_temperature, rssi_temperature_offset; ++ float current_temperature = 30.0; ++ float rssi_temperature_offset; + + /* Check that AGC/ARB firmwares are not corrupted, and update internal counter */ + /* WARNING: this needs to be called regularly by the upper layer */ +@@ -802,11 +805,11 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { + } + + /* Apply RSSI temperature compensation */ +- res = stts751_get_temperature(ts_fd, ts_addr, ¤t_temperature); +- if (res != LGW_I2C_SUCCESS) { +- printf("ERROR: failed to get current temperature\n"); +- return LGW_HAL_ERROR; +- } ++ //res = stts751_get_temperature(ts_fd, ts_addr, ¤t_temperature); ++ //if (res != LGW_I2C_SUCCESS) { ++ // printf("ERROR: failed to get current temperature\n"); ++ // return LGW_HAL_ERROR; ++ //} + + /* Iterate on the RX buffer to get parsed packets */ + for (nb_pkt_found = 0; nb_pkt_found < ((nb_pkt_fetched <= max_pkt) ? nb_pkt_fetched : max_pkt); nb_pkt_found++) { +@@ -982,10 +985,10 @@ int lgw_get_eui(uint64_t* eui) { + + int lgw_get_temperature(float* temperature) { + CHECK_NULL(temperature); +- +- if (stts751_get_temperature(ts_fd, ts_addr, temperature) != LGW_I2C_SUCCESS) { +- return LGW_HAL_ERROR; +- } ++ *temperature = 30.0; ++ //if (stts751_get_temperature(ts_fd, ts_addr, temperature) != LGW_I2C_SUCCESS) { ++ // return LGW_HAL_ERROR; ++ //} + + return LGW_HAL_SUCCESS; + } +diff --git a/libloragw/src/loragw_stts751.c b/libloragw/src/loragw_stts751.c +deleted file mode 100644 +index c417dc2..0000000 +--- a/libloragw/src/loragw_stts751.c ++++ /dev/null +@@ -1,186 +0,0 @@ +-/* +- / _____) _ | | +-( (____ _____ ____ _| |_ _____ ____| |__ +- \____ \| ___ | (_ _) ___ |/ ___) _ \ +- _____) ) ____| | | || |_| ____( (___| | | | +-(______/|_____)_|_|_| \__)_____)\____)_| |_| +- (C)2019 Semtech +- +-Description: +- Basic driver for ST ts751 temperature sensor +- +-License: Revised BSD License, see LICENSE.TXT file include in the project +-*/ +- +- +-/* -------------------------------------------------------------------------- */ +-/* --- DEPENDANCIES --------------------------------------------------------- */ +- +-#include /* C99 types */ +-#include /* bool type */ +-#include /* printf fprintf */ +- +-#include "loragw_i2c.h" +-#include "loragw_stts751.h" +- +-/* -------------------------------------------------------------------------- */ +-/* --- PRIVATE MACROS ------------------------------------------------------- */ +- +-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +-#if DEBUG_I2C == 1 +- #define DEBUG_MSG(str) fprintf(stderr, str) +- #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) +- #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;} +-#else +- #define DEBUG_MSG(str) +- #define DEBUG_PRINTF(fmt, args...) +- #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;} +-#endif +- +-/* -------------------------------------------------------------------------- */ +-/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ +- +-#define STTS751_REG_TEMP_H 0x00 +-#define STTS751_REG_STATUS 0x01 +-#define STTS751_STATUS_TRIPT BIT(0) +-#define STTS751_STATUS_TRIPL BIT(5) +-#define STTS751_STATUS_TRIPH BIT(6) +-#define STTS751_REG_TEMP_L 0x02 +-#define STTS751_REG_CONF 0x03 +-#define STTS751_CONF_RES_MASK 0x0C +-#define STTS751_CONF_RES_SHIFT 2 +-#define STTS751_CONF_EVENT_DIS BIT(7) +-#define STTS751_CONF_STOP BIT(6) +-#define STTS751_REG_RATE 0x04 +-#define STTS751_REG_HLIM_H 0x05 +-#define STTS751_REG_HLIM_L 0x06 +-#define STTS751_REG_LLIM_H 0x07 +-#define STTS751_REG_LLIM_L 0x08 +-#define STTS751_REG_TLIM 0x20 +-#define STTS751_REG_HYST 0x21 +-#define STTS751_REG_SMBUS_TO 0x22 +- +-#define STTS751_REG_PROD_ID 0xFD +-#define STTS751_REG_MAN_ID 0xFE +-#define STTS751_REG_REV_ID 0xFF +- +-#define STTS751_0_PROD_ID 0x00 +-#define STTS751_1_PROD_ID 0x01 +-#define ST_MAN_ID 0x53 +- +-/* -------------------------------------------------------------------------- */ +-/* --- PRIVATE VARIABLES ---------------------------------------------------- */ +- +-/* -------------------------------------------------------------------------- */ +-/* --- INTERNAL SHARED VARIABLES -------------------------------------------- */ +- +-/* -------------------------------------------------------------------------- */ +-/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */ +- +-/* -------------------------------------------------------------------------- */ +-/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ +- +-int stts751_configure(int i2c_fd, uint8_t i2c_addr) { +- int err; +- uint8_t val; +- +- /* Check Input Params */ +- if (i2c_fd <= 0) { +- printf("ERROR: invalid I2C file descriptor\n"); +- return LGW_I2C_ERROR; +- } +- +- DEBUG_PRINTF("INFO: configuring STTS751 temperature sensor on 0x%02X...\n", i2c_addr); +- +- /* Get product ID and test which sensor is mounted */ +- err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_PROD_ID, &val); +- if (err != 0) { +- DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); +- return LGW_I2C_ERROR; +- } +- switch (val) { +- case STTS751_0_PROD_ID: +- DEBUG_MSG("INFO: Product ID: STTS751-0\n"); +- break; +- case STTS751_1_PROD_ID: +- DEBUG_MSG("INFO: Product ID: STTS751-1\n"); +- break; +- default: +- printf("ERROR: Product ID: UNKNOWN\n"); +- return LGW_I2C_ERROR; +- } +- +- /* Get Manufacturer ID */ +- err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_MAN_ID, &val); +- if (err != 0) { +- DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); +- return LGW_I2C_ERROR; +- } +- if (val != ST_MAN_ID) { +- printf("ERROR: Manufacturer ID: UNKNOWN\n"); +- return LGW_I2C_ERROR; +- } else { +- DEBUG_PRINTF("INFO: Manufacturer ID: 0x%02X\n", val); +- } +- +- /* Get revision number */ +- err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_REV_ID, &val); +- if (err != 0) { +- DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); +- return LGW_I2C_ERROR; +- } +- DEBUG_PRINTF("INFO: Revision number: 0x%02X\n", val); +- +- /* Set conversion resolution to 12 bits */ +- err = i2c_linuxdev_write(i2c_fd, i2c_addr, STTS751_REG_CONF, 0x8C); /* TODO: do not hardcode the whole byte */ +- if (err != 0) { +- DEBUG_PRINTF("ERROR: failed to write I2C device 0x%02X (err=%i)\n", i2c_addr, err); +- return LGW_I2C_ERROR; +- } +- +- /* Set conversion rate to 1 / second */ +- err = i2c_linuxdev_write(i2c_fd, i2c_addr, STTS751_REG_RATE, 0x04); +- if (err != 0) { +- DEBUG_PRINTF("ERROR: failed to write I2C device 0x%02X (err=%i)\n", i2c_addr, err); +- return LGW_I2C_ERROR; +- } +- +- return LGW_I2C_SUCCESS; +-} +- +-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +- +-int stts751_get_temperature(int i2c_fd, uint8_t i2c_addr, float * temperature) { +- int err; +- uint8_t high_byte, low_byte; +- int8_t h; +- +- /* Check Input Params */ +- if (i2c_fd <= 0) { +- printf("ERROR: invalid I2C file descriptor\n"); +- return LGW_I2C_ERROR; +- } +- +- /* Read Temperature LSB */ +- err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_TEMP_L, &low_byte); +- if (err != 0) { +- printf("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); +- return LGW_I2C_ERROR; +- } +- +- /* Read Temperature MSB */ +- err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_TEMP_H, &high_byte); +- if (err != 0) { +- printf("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err); +- return LGW_I2C_ERROR; +- } +- +- h = (int8_t)high_byte; +- *temperature = ((h << 8) | low_byte) / 256.0; +- +- DEBUG_PRINTF("Temperature: %f C (h:0x%02X l:0x%02X)\n", *temperature, high_byte, low_byte); +- +- return LGW_I2C_SUCCESS; +-} +- +-/* --- EOF ------------------------------------------------------------------ */ From f511eca6101013f84a26715caffe65faaa33fcdf Mon Sep 17 00:00:00 2001 From: Rahul Thakoor Date: Tue, 22 Sep 2020 14:55:41 +0400 Subject: [PATCH 16/88] Add support for both RAK2245 and RAK2287 via env vars Change-type: major Signed-off-by: Rahul Thakoor --- Dockerfile.template | 25 +++++++++++++--------- start-corecell.sh | 47 ---------------------------------------- start.sh | 52 ++++++++++++++++++++++++++++++--------------- 3 files changed, 50 insertions(+), 74 deletions(-) delete mode 100644 start-corecell.sh diff --git a/Dockerfile.template b/Dockerfile.template index 65b0740d..42e5a84d 100644 --- a/Dockerfile.template +++ b/Dockerfile.template @@ -1,12 +1,6 @@ -FROM balenalib/%%BALENA_MACHINE_NAME%%-debian:stretch +FROM balenalib/%%BALENA_MACHINE_NAME%%-debian:buster-build as builder +# Install build tools and remove layer cache afterwards -# Install build tools and remove layer cache afterwards -RUN apt-get -q update && apt-get install -yq --no-install-recommends \ - build-essential \ - git \ - && apt-get clean && rm -rf /var/lib/apt/lists/* - -RUN install_packages jq # Switch to working directory for our app WORKDIR /usr/src/app @@ -15,8 +9,19 @@ WORKDIR /usr/src/app COPY . . # Compile our source code -#RUN make platform=rpi variant=std arch=%%BALENA_ARCH%% +RUN make platform=rpi variant=std arch=%%BALENA_ARCH%% RUN make platform=corecell variant=std arch=%%BALENA_ARCH%% + +FROM balenalib/%%BALENA_MACHINE_NAME%%-debian:buster + +RUN install_packages jq + +WORKDIR /usr/src/app + +COPY --from=builder /usr/src/app/ ./ + +COPY start.sh ./ + # Launch our binary on container startup. -CMD ["bash", "start-corecell.sh"] +CMD ["bash", "start.sh"] diff --git a/start-corecell.sh b/start-corecell.sh deleted file mode 100644 index 92cb6322..00000000 --- a/start-corecell.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash - -TAG_KEY="EUI" -TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g') - -echo $TTN_EUI - -ID=$(curl -sX GET "https://api.balena-cloud.com/v5/device?\$filter=uuid%20eq%20'$BALENA_DEVICE_UUID'" \ --H "Content-Type: application/json" \ --H "Authorization: Bearer $BALENA_API_KEY" | \ -jq ".d | .[0] | .id") - -TAG=$(curl -sX POST \ -"https://api.balena-cloud.com/v5/device_tag" \ --H "Content-Type: application/json" \ --H "Authorization: Bearer $BALENA_API_KEY" \ ---data "{ \"device\": \"$ID\", \"tag_key\": \"$TAG_KEY\", \"value\": \"$TTN_EUI\" }" > /dev/null) - - -# declare map of hardware pins to GPIO on Raspberry Pi -declare -a pinToGPIO -pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) - -cd examples/corecell - -# Default to TTN server -TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)} - - -GW_RESET_PIN=${GW_RESET_PIN:-22} -GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} - -# Setup TC files from environment -echo $TC_URI > ./lns-ttn/tc.uri -echo "$TC_TRUST" > ./lns-ttn/tc.trust - -# Reset gateway -#echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" -#echo $GW_RESET_GPIO > /sys/class/gpio/export -#echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction -#echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -#echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -#echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -#echo $GW_RESET_GPIO > /sys/class/gpio/unexport - -./start-station.sh -l ./lns-ttn diff --git a/start.sh b/start.sh index 02e1f580..0674465a 100644 --- a/start.sh +++ b/start.sh @@ -21,29 +21,47 @@ TAG=$(curl -sX POST \ declare -a pinToGPIO pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) - -cd examples/live-s2.sm.tc +if [ -z ${MODEL} ] ; + then + echo -e "\033[91mWARNING: MODEL variable not set.\n Set the model of the gateway you are using." + balena-idle + else + if [ $MODEL = "RAK2245" ];then + cd examples/live-s2.sm.tc + fi + if [ $MODEL = "RAK2287" ];then + cd examples/corecell + fi +fi # Default to TTN server TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} - GW_RESET_PIN=${GW_RESET_PIN:-22} GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} -# Setup TC files from environment -echo $TC_URI > ./lns-ttn/tc.uri -echo "$TC_TRUST" > ./lns-ttn/tc.trust - -# Reset gateway -#echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" -#echo $GW_RESET_GPIO > /sys/class/gpio/export -#echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction -#echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -#echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -#echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value -#echo $GW_RESET_GPIO > /sys/class/gpio/unexport + +if [ $MODEL = "RAK2245" ];then + # Setup TC files from environment + echo $TC_URI > tc.uri + echo "$TC_TRUST" > tc.trust + + # Reset gateway + echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" + echo $GW_RESET_GPIO > /sys/class/gpio/export + echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction + echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value + echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value + echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value + echo $GW_RESET_GPIO > /sys/class/gpio/unexport + RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station +fi +if [ $MODEL = "RAK2287" ];then + # Setup TC files from environment + echo $TC_URI > ./lns-ttn/tc.uri + echo "$TC_TRUST" > ./lns-ttn/tc.trust -#RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station -./start-station.sh -l ./lns-ttn + ./start-station.sh -l ./lns-ttn +fi +balena-idle From 836fcea48c4f34e75a75c229135ec686a593d944 Mon Sep 17 00:00:00 2001 From: mpous Date: Tue, 22 Sep 2020 13:31:19 +0200 Subject: [PATCH 17/88] README and balena.yml update --- README.md | 23 +++++++++++++++++++---- balena.yml | 3 +++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 738569cb..f1b20617 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# LoRa Basics™ Station using balena.io and RAK2287 +# LoRa Basics™ Station using balena.io and RAK2245 and RAK 2287 -This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2287 concentrator with a Pi Hat. +This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 and RAK2287 concentrator with a Pi Hat. ## Introduction @@ -15,9 +15,14 @@ The Basics Station protocol enables the LoRa gateways with a reliable and secure ### Hardware * Raspberry Pi 4 or [balenaFin](https://www.balena.io/fin/) +* SD card in case of the RPi 4 + * [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) * [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) -* SD card in case of the RPi 4 + +or + +* [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) ### Software @@ -63,6 +68,15 @@ If that does not work, go to the terminal box and click "Select a target", then Copy the result and you are ready to register your gateway with this EUI. +#### Define your MODEL + +In case that your LoRa concentrator is a RAK2287, it's important to change the Device Variable with the correct MODEL. + +1. Go to balenaCloud dashboard and get into your LoRa gateway device site. +2. Click "Device Variables" button on the left menu and change the MODEL variable to RAK2287. + +That enables a fleet of LoRa gateways with both RAK2245 and RAK2287 together under the same app. + ### Configure your The Things Network gateway @@ -93,7 +107,8 @@ Variable Name | Value | Description | Default **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2287 uses SPI to communicate and needs to use a specific speed | 2000000 -**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` +**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443`` +**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. diff --git a/balena.yml b/balena.yml index ccd337cd..39836fa0 100644 --- a/balena.yml +++ b/balena.yml @@ -4,3 +4,6 @@ applicationEnvironmentVariables: - GW_RESET_PIN: 11 - SPI_SPEED: 2000000 - TC_URI: wss://lns.eu.thethings.network:443 + - MODEL: RAK2245 + - REGION: eu + From 3f24b3edf303be0b9cca274c0f5fd70e121dcb2c Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 22 Sep 2020 13:32:06 +0200 Subject: [PATCH 18/88] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1b20617..5cc5c007 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# LoRa Basics™ Station using balena.io and RAK2245 and RAK 2287 +# LoRa Basics™ Station using balena.io and RAK2245 or RAK 2287 This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 and RAK2287 concentrator with a Pi Hat. From 44f6122b8fa1cce5cb9ba93c3f9d2d6bc495b97e Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 22 Sep 2020 13:36:35 +0200 Subject: [PATCH 19/88] Update README.md --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5cc5c007..3f92713b 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,17 @@ If you are a balena CLI expert, feel free to use balena CLI. ## Configure the Gateway -### Before configure your LoRa gateway +### Define your MODEL + +In case that your LoRa concentrator is a ```RAK2287```, it's important to change the Device Variable with the correct MODEL. The default MODEL on the balena Application is the ```RAK2245```. + +1. Go to balenaCloud dashboard and get into your LoRa gateway device site. +2. Click "Device Variables" button on the left menu and change the MODEL variable to ```RAK2287```. + +That enables a fleet of LoRa gateways with both ```RAK2245``` and ```RAK2287``` together under the same app. + + +### Get the EUI of the LoRa Gateway The LoRa gateways are manufactured with a unique 64 bits (8 bytes) identifier, called EUI, which can be used to register the gateway on The Things Network. To get the EUI from your board it’s important to know the Ethernet MAC address of it. The TTN EUI will be the Ethernet mac address (6 bytes), which is unique, expanded with 2 more bytes (FFFE). This is a standard way to increment the MAC address from 6 to 8 bytes. @@ -68,15 +78,6 @@ If that does not work, go to the terminal box and click "Select a target", then Copy the result and you are ready to register your gateway with this EUI. -#### Define your MODEL - -In case that your LoRa concentrator is a RAK2287, it's important to change the Device Variable with the correct MODEL. - -1. Go to balenaCloud dashboard and get into your LoRa gateway device site. -2. Click "Device Variables" button on the left menu and change the MODEL variable to RAK2287. - -That enables a fleet of LoRa gateways with both RAK2245 and RAK2287 together under the same app. - ### Configure your The Things Network gateway From c2d680f90923e3d2ce65b06d1fc30b9400d3f8f9 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 22 Sep 2020 13:37:33 +0200 Subject: [PATCH 20/88] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f92713b..2e136a03 100644 --- a/README.md +++ b/README.md @@ -58,10 +58,10 @@ If you are a balena CLI expert, feel free to use balena CLI. ### Define your MODEL -In case that your LoRa concentrator is a ```RAK2287```, it's important to change the Device Variable with the correct MODEL. The default MODEL on the balena Application is the ```RAK2245```. +In case that your LoRa concentrator is a ```RAK2287```, it's important to change the Device Variable with the correct ```MODEL```. The default ```MODEL``` on the balena Application is the ```RAK2245```. 1. Go to balenaCloud dashboard and get into your LoRa gateway device site. -2. Click "Device Variables" button on the left menu and change the MODEL variable to ```RAK2287```. +2. Click "Device Variables" button on the left menu and change the ```MODEL``` variable to ```RAK2287```. That enables a fleet of LoRa gateways with both ```RAK2245``` and ```RAK2287``` together under the same app. From 8a438d4821f56212e6cc881eae8e7462c8761a44 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 22 Sep 2020 13:39:34 +0200 Subject: [PATCH 21/88] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e136a03..e8c2ef64 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# LoRa Basics™ Station using balena.io and RAK2245 or RAK 2287 +# LoRa Basics™ Station using balena.io with RAK2245 or RAK 2287 concentrators This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 and RAK2287 concentrator with a Pi Hat. @@ -17,6 +17,8 @@ The Basics Station protocol enables the LoRa gateways with a reliable and secure * Raspberry Pi 4 or [balenaFin](https://www.balena.io/fin/) * SD card in case of the RPi 4 +#### LoRa Concentrators + * [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) * [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) @@ -108,7 +110,7 @@ Variable Name | Value | Description | Default **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2287 uses SPI to communicate and needs to use a specific speed | 2000000 -**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443`` +**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` **`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` From 856329eace7c9a9ade280312f999597962ec6be4 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 22 Sep 2020 13:40:08 +0200 Subject: [PATCH 22/88] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e8c2ef64..c0103a82 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Variable Name | Value | Description | Default **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2287 uses SPI to communicate and needs to use a specific speed | 2000000 **`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` -**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` +**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | ```RAK2245``` At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. From a46c95212fbbe41358018609921f8359518e72ad Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 22 Sep 2020 14:20:48 +0200 Subject: [PATCH 23/88] Update balena.yml --- balena.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/balena.yml b/balena.yml index 39836fa0..2d100113 100644 --- a/balena.yml +++ b/balena.yml @@ -4,6 +4,4 @@ applicationEnvironmentVariables: - GW_RESET_PIN: 11 - SPI_SPEED: 2000000 - TC_URI: wss://lns.eu.thethings.network:443 - - MODEL: RAK2245 - - REGION: eu - + - MODEL: RAK2245 From 77cfd66622efd88a032e02c27d09b6a63b7b03d8 Mon Sep 17 00:00:00 2001 From: Rahul Thakoor Date: Tue, 22 Sep 2020 16:26:00 +0400 Subject: [PATCH 24/88] Use separate start scripts Change-type: patch Signed-off-by: Rahul Thakoor --- Dockerfile.template | 2 +- start.sh | 39 ++++----------------------------------- start_rak2245.sh | 32 ++++++++++++++++++++++++++++++++ start_rak2287.sh | 16 ++++++++++++++++ 4 files changed, 53 insertions(+), 36 deletions(-) create mode 100755 start_rak2245.sh create mode 100755 start_rak2287.sh diff --git a/Dockerfile.template b/Dockerfile.template index 42e5a84d..af638d48 100644 --- a/Dockerfile.template +++ b/Dockerfile.template @@ -21,7 +21,7 @@ WORKDIR /usr/src/app COPY --from=builder /usr/src/app/ ./ -COPY start.sh ./ +COPY start* ./ # Launch our binary on container startup. CMD ["bash", "start.sh"] diff --git a/start.sh b/start.sh index 0674465a..5881d271 100644 --- a/start.sh +++ b/start.sh @@ -17,51 +17,20 @@ TAG=$(curl -sX POST \ --data "{ \"device\": \"$ID\", \"tag_key\": \"$TAG_KEY\", \"value\": \"$TTN_EUI\" }" > /dev/null) -# declare map of hardware pins to GPIO on Raspberry Pi -declare -a pinToGPIO -pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) if [ -z ${MODEL} ] ; then echo -e "\033[91mWARNING: MODEL variable not set.\n Set the model of the gateway you are using." balena-idle else + echo "Using MODEL: $MODEL" if [ $MODEL = "RAK2245" ];then - cd examples/live-s2.sm.tc + ./start_rak2245.sh + fi if [ $MODEL = "RAK2287" ];then - cd examples/corecell + ./start_rak2287.sh fi fi -# Default to TTN server -TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} -GW_RESET_PIN=${GW_RESET_PIN:-22} -GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} - - -if [ $MODEL = "RAK2245" ];then - # Setup TC files from environment - echo $TC_URI > tc.uri - echo "$TC_TRUST" > tc.trust - - # Reset gateway - echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" - echo $GW_RESET_GPIO > /sys/class/gpio/export - echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction - echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value - echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value - echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value - echo $GW_RESET_GPIO > /sys/class/gpio/unexport - RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station -fi -if [ $MODEL = "RAK2287" ];then - # Setup TC files from environment - echo $TC_URI > ./lns-ttn/tc.uri - echo "$TC_TRUST" > ./lns-ttn/tc.trust - - ./start-station.sh -l ./lns-ttn -fi -balena-idle diff --git a/start_rak2245.sh b/start_rak2245.sh new file mode 100755 index 00000000..1e314641 --- /dev/null +++ b/start_rak2245.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +cd examples/live-s2.sm.tc + +# declare map of hardware pins to GPIO on Raspberry Pi +declare -a pinToGPIO +pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) + +# Default to TTN server +TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} +TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} + + +GW_RESET_PIN=${GW_RESET_PIN:-11} +GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} + +# Setup TC files from environment +echo $TC_URI > tc.uri +echo "$TC_TRUST" > tc.trust + +# Reset gateway +echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" +echo $GW_RESET_GPIO > /sys/class/gpio/export +echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction +echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +echo $GW_RESET_GPIO > /sys/class/gpio/unexport + +RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station + +balena-idle diff --git a/start_rak2287.sh b/start_rak2287.sh new file mode 100755 index 00000000..c8552bfe --- /dev/null +++ b/start_rak2287.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +cd examples/corecell + +# Default to TTN server +TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} +TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} + + +# Setup TC files from environment +echo $TC_URI > ./lns-ttn/tc.uri +echo "$TC_TRUST" > ./lns-ttn/tc.trust + +./start-station.sh -l ./lns-ttn + +balena-idle From 27098a5210a0c0d15c9e415a89974e498e60a5b3 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 22 Sep 2020 14:34:58 +0200 Subject: [PATCH 25/88] Delete README-balena.md Outdated README balena version --- README-balena.md | 103 ----------------------------------------------- 1 file changed, 103 deletions(-) delete mode 100644 README-balena.md diff --git a/README-balena.md b/README-balena.md deleted file mode 100644 index 5b0533dc..00000000 --- a/README-balena.md +++ /dev/null @@ -1,103 +0,0 @@ -# LoRa Basics™ Station using balena.io and RAK2245 - -This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 Pi Hat. - - -## Introduction - -Deploy a The Things Network (TTN) LoRa gateway running the basics station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. - -The Basics Station protocol enables the LoRa gateways with a reliable and secure communication between the gateways and the cloud and it is becoming the standard Packet Forward protocol used by most of the LoRaWAN operators. - - -## Getting started - -### Hardware - -* Raspberry Pi 4 or [balenaFin](https://www.balena.io/fin/) -* [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) -* SD card in case of the RPi 4 - -### Software - -* A TTN account ([sign up here](https://console.thethingsnetwork.org) -* A balenaCloud account ([sign up here](https://dashboard.balena-cloud.com/) -* [balenaEtcher](https://balena.io/etcher) - -Once all of this is ready, you are able to deploy this repository following instructions below. - -## Deploy the code - -### Via [Balena Deploy](https://www.balena.io/docs/learn/deploy/deploy-with-balena-button/) - -Running this project is as simple as deploying it to a balenaCloud application. You can do it in just one click by using the button below: - -[![](https://www.balena.io/deploy.png)](https://dashboard.balena-cloud.com/deploy?repoUrl=https://github.com/balena-io-playground/basicstation) - -Follow instructions, click Add a Device and flash an SD card with that OS image dowloaded from balenaCloud. Enjoy the magic 🌟Over-The-Air🌟! - - -### Via [Balena-Cli](https://www.balena.io/docs/reference/balena-cli/) - -If you are a balena CLI expert, feel free to use balena CLI. - -- Sign up on [balena.io](https://dashboard.balena.io/signup) -- Create a new application on balenaCloud. -- Clone this repository to your local workspace. -- Using [Balena CLI](https://www.balena.io/docs/reference/cli/), push the code with `balena push ` -- See the magic happening, your device is getting updated 🌟Over-The-Air🌟! - - -## Configure the Gateway - -### Before configure your LoRa gateway - -The LoRa gateways are manufactured with a unique 64 bits (8 bytes) identifier, called EUI, which can be used to register the gateway on The Things Network. To get the EUI from your board it’s important to know the Ethernet MAC address of it. The TTN EUI will be the Ethernet mac address (6 bytes), which is unique, expanded with 2 more bytes (FFFE). This is a standard way to increment the MAC address from 6 to 8 bytes. - -To get the EUI, copy the TAG of the device which will be generated automatically when the device gets provisioned on balenaCloud. - -If that does not work, go to the terminal box and click "Select a target", then “HostOS”. Once you are inside the shell, type: - -```cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g' ``` - -Copy the result and you are ready to register your gateway with this EUI. - - -### Configure your The Things Network gateway - -1. Sign up at [The Things Network console](https://console.thethingsnetwork.org/). -2. Click Gateways button. -3. Click the "Register gateway" link. -4. Check “I’m using the legacy packet forwarder” checkbox. -5. Paste the EUI from the Ethernet mac address of the board (calculated above) -6. Complete the form and click Register gateway. - - -### Balena LoRa Basics Station Service Variables - -Once successfully registered, copy the The Things Network gateway KEY to configure your board variables on balenaCloud. - -1. Go to balenaCloud dashboard and get into your LoRa gateway device site. -2. Click "Device Variables" button on the left menu and add these variables. - -Most of the variables have been generated automatically when the Application has been created with the Deploy with Balena button. However it's important to introduce the `GW_ID`and `GW_KEY`from the The Things Network console. - - -Variable Name | Value | Description | Default ------------- | ------------- | ------------- | ------------- -**`GW_GPS`** | `STRING` | Enables GPS | true or false -**`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) -**`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) -**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 -**`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2245 uses SPI to communicate and needs to use a specific speed | 20000000 -**`TC_URI`** | `STRING` | basics station TC URI to get connected | ```wss://lns.eu.thethings.network:443``` - - -At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. - - -## Attribution - -- This is an adaptation of the [Semtech Basics Station repository](https://github.com/lorabasics/basicstation). Documentation [here](https://doc.sm.tc/station). -- This is in part working thanks of the work of Jose Marcelino from RAK Wireless and Marc Pous from balena.io. -- This is in part based on excellent work done by the Balena.io Hardware Hackers team. From b525b5533e4f3101168ea97cc5f578b010154c6f Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 23 Sep 2020 10:51:09 +0200 Subject: [PATCH 26/88] Update balena.yml Added GW_ID and GW_KEY and deleted SPI_SPEED as it was not possible to modify the value of the SPI SPEED --- balena.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/balena.yml b/balena.yml index 2d100113..9248c588 100644 --- a/balena.yml +++ b/balena.yml @@ -2,6 +2,7 @@ applicationEnvironmentVariables: - GW_GPS: false - GW_RESET_PIN: 11 - - SPI_SPEED: 2000000 - TC_URI: wss://lns.eu.thethings.network:443 - - MODEL: RAK2245 + - MODEL: RAK2245 + - GW_ID: 0 + - GW_KEY: 0 From 3f5d2f7d472c91ca24d082930b4b277be44fcfc5 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 23 Sep 2020 11:50:40 +0200 Subject: [PATCH 27/88] Update README.md --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c0103a82..d9b2f135 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ In case that your LoRa concentrator is a ```RAK2287```, it's important to change That enables a fleet of LoRa gateways with both ```RAK2245``` and ```RAK2287``` together under the same app. +Before starting check the region where you are going to deploy the gateway, de facto configuration is for EU gateways. Change the ```TC_URI```if you are in a different zone than European. + ### Get the EUI of the LoRa Gateway @@ -93,14 +95,12 @@ Copy the result and you are ready to register your gateway with this EUI. ### Balena LoRa Basics Station Service Variables -Once successfully registered, copy the The Things Network gateway KEY to configure your board variables on balenaCloud. +Once successfully registered, copy the The Things Network gateway KEY and ID to configure your board variables on balenaCloud. 1. Go to balenaCloud dashboard and get into your LoRa gateway device site. 2. Click "Device Variables" button on the left menu and add these variables. -Most of the variables have been generated automatically when the Application has been created with the Deploy with Balena button. Before starting check the region where you are going to deploy the gateway, de facto configuration is for EU gateways. Change the ```TC_URI```if you are in a different zone than European. - -And it's important to introduce the `GW_ID`and `GW_KEY`from the The Things Network console. +The `GW_ID`and `GW_KEY` variables have been generated automatically when the Application has been created with the Deploy with Balena button. Replace the values with the KEY and ID from the TTN console. Variable Name | Value | Description | Default @@ -109,17 +109,18 @@ Variable Name | Value | Description | Default **`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 -**`SPI_SPEED`** | `STRING` | The Raspberry Pi and RAK2287 uses SPI to communicate and needs to use a specific speed | 2000000 **`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` **`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | ```RAK2245``` At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. +It's possible that on the TTN Console the gateway appears as Not connected if it's not receiving any LoRa message. Sometimes the websockets connection among the LoRa Gateway and the server can get broken. However a new LoRa package will re-open the websocket between the Gateway and TTN or TTI. This issue should be solved with the TTN v3. + ## Attribution - This is an adaptation of the [Semtech Basics Station repository](https://github.com/lorabasics/basicstation). Documentation [here](https://doc.sm.tc/station). - This is in part working thanks of the work of Jose Marcelino from RAK Wireless and Marc Pous from balena.io. -- This is in part based on excellent work done by the Balena.io Hardware Hackers team. +- This is in part based on excellent work done by Rahul Thakoor from the Balena.io Hardware Hackers team. From 62a925d544895810c6b79d3a4ba8aebcd02abae0 Mon Sep 17 00:00:00 2001 From: mpous Date: Tue, 3 Nov 2020 14:59:34 +0100 Subject: [PATCH 28/88] Creating corecell armv7hf --- setup.gmk | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.gmk b/setup.gmk index 8a05246c..335edb6c 100644 --- a/setup.gmk +++ b/setup.gmk @@ -45,6 +45,7 @@ ARCH.linux.default = x86_64-linux-gnu ARCH.linuxV2.default = x86_64-linux-gnu ARCH.linuxpico.default = x86_64-linux-gnu ARCH.corecell.default = arm-linux-gnueabihf +ARCH.corecell.armv7hf = arm-linux-gnueabihf ARCH.corecell.aarch64 = aarch64-linux-gnu ARCH.rpi.armv7hf = arm-linux-gnueabihf ARCH.rpi.aarch64 = aarch64-linux-gnu From 353721ab2e0b27f2866fd5d92559dabb2109b356 Mon Sep 17 00:00:00 2001 From: mpous Date: Tue, 3 Nov 2020 15:15:10 +0100 Subject: [PATCH 29/88] adding default arch on rpi --- setup.gmk | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.gmk b/setup.gmk index 335edb6c..c0c7e428 100644 --- a/setup.gmk +++ b/setup.gmk @@ -47,6 +47,7 @@ ARCH.linuxpico.default = x86_64-linux-gnu ARCH.corecell.default = arm-linux-gnueabihf ARCH.corecell.armv7hf = arm-linux-gnueabihf ARCH.corecell.aarch64 = aarch64-linux-gnu +ARCH.rpi.default = arm-linux-gnueabihf ARCH.rpi.armv7hf = arm-linux-gnueabihf ARCH.rpi.aarch64 = aarch64-linux-gnu ARCH.kerlink.default = arm-klk-linux-gnueabi From 92cc8118b2ba0de6f1fe2339b8e4a88fd99f1373 Mon Sep 17 00:00:00 2001 From: mpous Date: Wed, 25 Nov 2020 15:01:27 +0100 Subject: [PATCH 30/88] Add contract balena.yml --- balena.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/balena.yml b/balena.yml index 9248c588..5eac8f12 100644 --- a/balena.yml +++ b/balena.yml @@ -1,8 +1,23 @@ - -applicationEnvironmentVariables: +version: "2" +slug: "balena-basicstation" +name: "basicstation" +type: "sw.application" +assets: + - url: "https://github.com/balenalabs/basicstation" + name: "repository" + - url: "https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png" + name: "logo" +data: + description: "Deploys a TTN LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi with a RAK2245 and 2287 concentrator with a Pi Hat." + applicationEnvironmentVariables: - GW_GPS: false - GW_RESET_PIN: 11 - TC_URI: wss://lns.eu.thethings.network:443 - MODEL: RAK2245 - GW_ID: 0 - GW_KEY: 0 + defaultDeviceType: "raspberry-pi" + supportedDeviceTypes: + - "raspberrypi3" + - "raspberrypi4-64" + - "fincm3" From d3db57f79e78dbd20750ddd54fd827a5f0c22825 Mon Sep 17 00:00:00 2001 From: mpous Date: Wed, 25 Nov 2020 15:03:31 +0100 Subject: [PATCH 31/88] Add contract balena.yml --- balena.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index 5eac8f12..7333847c 100644 --- a/balena.yml +++ b/balena.yml @@ -8,7 +8,7 @@ assets: - url: "https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png" name: "logo" data: - description: "Deploys a TTN LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi with a RAK2245 and 2287 concentrator with a Pi Hat." + description: "Deploys a TTN LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi with a RAK2245 and 2287 concentrators." applicationEnvironmentVariables: - GW_GPS: false - GW_RESET_PIN: 11 @@ -19,5 +19,6 @@ data: defaultDeviceType: "raspberry-pi" supportedDeviceTypes: - "raspberrypi3" + - "raspberrypi3-64" - "raspberrypi4-64" - "fincm3" From 7264a3f4c4a9666389c8de2dad600f4671794724 Mon Sep 17 00:00:00 2001 From: mpous Date: Wed, 25 Nov 2020 15:20:26 +0100 Subject: [PATCH 32/88] Modify contract balena.yml --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index 7333847c..d69086ec 100644 --- a/balena.yml +++ b/balena.yml @@ -16,7 +16,7 @@ data: - MODEL: RAK2245 - GW_ID: 0 - GW_KEY: 0 - defaultDeviceType: "raspberry-pi" + defaultDeviceType: "raspberrypi3" supportedDeviceTypes: - "raspberrypi3" - "raspberrypi3-64" From 5c701cfa4bc006e27a6426fba96424ec4cac612e Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 25 Nov 2020 15:52:45 +0100 Subject: [PATCH 33/88] Add logo.png --- logo.png | Bin 0 -> 48319 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 logo.png diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e4f7a19b7770a278d692479c5e98aaaa861347e8 GIT binary patch literal 48319 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 a{RWp%i6*@pp11u0_{m5pidTyo2mBw^N8dC6 literal 0 HcmV?d00001 From ac8a8bd57061c22642c26bf72ea6b2b59cd08031 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 16 Dec 2020 15:54:53 +0100 Subject: [PATCH 34/88] Update balena.yml --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index d69086ec..ab413b73 100644 --- a/balena.yml +++ b/balena.yml @@ -1,6 +1,6 @@ version: "2" slug: "balena-basicstation" -name: "basicstation" +name: "TTN basicstation gateway" type: "sw.application" assets: - url: "https://github.com/balenalabs/basicstation" From 0738365f9a0eee38e00d7dc9d973bf65a5488480 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 16 Dec 2020 15:55:43 +0100 Subject: [PATCH 35/88] Update balena.yml --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index ab413b73..9adba6af 100644 --- a/balena.yml +++ b/balena.yml @@ -1,6 +1,6 @@ version: "2" slug: "balena-basicstation" -name: "TTN basicstation gateway" +name: "TTN basicstation Gateway" type: "sw.application" assets: - url: "https://github.com/balenalabs/basicstation" From 9217cf591d6d5bada9d0ad7059265d6f028dc291 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 16 Dec 2020 16:03:47 +0100 Subject: [PATCH 36/88] Update balena.yml --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index 9adba6af..a86017de 100644 --- a/balena.yml +++ b/balena.yml @@ -8,7 +8,7 @@ assets: - url: "https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png" name: "logo" data: - description: "Deploys a TTN LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi with a RAK2245 and 2287 concentrators." + description: "Deploys a TTN LoRaWAN gateway with Basics Station Packet Forward protocol. It runs on a Raspberry Pi or Fin with a RAK2245 and 2287 concentrators." applicationEnvironmentVariables: - GW_GPS: false - GW_RESET_PIN: 11 From 5e735893557f18aeb8ba8537f964841407a865cf Mon Sep 17 00:00:00 2001 From: Jose Marcelino Date: Thu, 14 Jan 2021 13:06:03 +0000 Subject: [PATCH 37/88] Suppport TC_KEY variable Add a veriable to set token authentication (used for example the new Things Stack) --- start_rak2245.sh | 6 ++++++ start_rak2287.sh | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/start_rak2245.sh b/start_rak2245.sh index 1e314641..92a98cea 100755 --- a/start_rak2245.sh +++ b/start_rak2245.sh @@ -18,6 +18,12 @@ GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} echo $TC_URI > tc.uri echo "$TC_TRUST" > tc.trust +if [ ! -z ${TC_KEY} ]; then + echo "Authorization: Bearer $TC_KEY" | perl -p -e 's/\r\n|\n|\r/\r\n/g' > tc.key +fi + + + # Reset gateway echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" echo $GW_RESET_GPIO > /sys/class/gpio/export diff --git a/start_rak2287.sh b/start_rak2287.sh index c8552bfe..b9abf1d3 100755 --- a/start_rak2287.sh +++ b/start_rak2287.sh @@ -8,9 +8,14 @@ TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.tx # Setup TC files from environment -echo $TC_URI > ./lns-ttn/tc.uri +echo "$TC_URI" > ./lns-ttn/tc.uri echo "$TC_TRUST" > ./lns-ttn/tc.trust +if [ ! -z ${TC_KEY} ]; then + echo "Authorization: Bearer $TC_KEY" | perl -p -e 's/\r\n|\n|\r/\r\n/g' > ./lns-ttn/tc.key +fi + + ./start-station.sh -l ./lns-ttn balena-idle From 04dc1475b246f0e9401d168f379f2e6aa8fbd13a Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Mon, 18 Jan 2021 13:57:28 +0100 Subject: [PATCH 38/88] Update README.md Updated with The Things Stack changes --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d9b2f135..ce906631 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # LoRa Basics™ Station using balena.io with RAK2245 or RAK 2287 concentrators -This project deploys a TTN LoRa gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 and RAK2287 concentrator with a Pi Hat. +This project deploys a LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 and RAK2287 concentrator with a Pi Hat. ## Introduction -Deploy a The Things Network (TTN) LoRa gateway running the basics station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. +Deploy a The Things Network (TTN), The Things Industries (TTI) or The Things Stack (TTS) LoRaWAN gateway running the Basics Station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. The Basics Station protocol enables the LoRa gateways with a reliable and secure communication between the gateways and the cloud and it is becoming the standard Packet Forward protocol used by most of the LoRaWAN operators. @@ -89,17 +89,37 @@ Copy the result and you are ready to register your gateway with this EUI. 2. Click Gateways button. 3. Click the "Register gateway" link. 4. Check “I’m using the legacy packet forwarder” checkbox. -5. Paste the EUI from the Ethernet mac address of the board (calculated above) +5. Paste the EUI from the balenaCloud tag or the Ethernet mac address of the board (calculated above) 6. Complete the form and click Register gateway. +7. Copy the Key generated on the gateway page. + + +### Configure your The Things Stack gateway (The Things Conference 2021) + +1. Sign up at [The Things Stack console](https://ttc.eu1.cloud.thethings.industries/console/). +2. Click "Go to Gateways" icon. +3. Click the "Add gateway" button. +4. Introduce the data for the gateway. +5. Paste the EUI from the balenaCloud tags. +6. Complete the form and click Register gateway. +7. Once the gateway is created, click "API keys" link. +8. Click "Add API key" button. +9. Select "Grant individual rights" and then "Link as Gateway to a Gateway Server for traffic exchange ..." and then click "Create API key". +10. Copy the API key generated. and bring it to balenaCloud as ```TC_KEY```. + ### Balena LoRa Basics Station Service Variables -Once successfully registered, copy the The Things Network gateway KEY and ID to configure your board variables on balenaCloud. +Once successfully registered: 1. Go to balenaCloud dashboard and get into your LoRa gateway device site. 2. Click "Device Variables" button on the left menu and add these variables. +#### The Things Network Variables + +Remember to copy the The Things Network gateway KEY and ID to configure your board variables on balenaCloud. + The `GW_ID`and `GW_KEY` variables have been generated automatically when the Application has been created with the Deploy with Balena button. Replace the values with the KEY and ID from the TTN console. @@ -113,7 +133,25 @@ Variable Name | Value | Description | Default **`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | ```RAK2245``` -At this moment your The Things Network gateway should be up and running. Check on the TTN console if it shows the connected status. +#### The Things Stack Variables + +Remember to generate an API Key and copy it. It will be the ```TC_KEY```. + + +Variable Name | Value | Description | Default +------------ | ------------- | ------------- | ------------- +**`GW_GPS`** | `STRING` | Enables GPS | true or false +**`TC_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) +**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 +**`TC_URI`** | `STRING` | Gateway Server address. If you are in the EU region use ```wss://ttc.eu1.cloud.thethings.industries:8887``` +**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | ```RAK2245``` + + + +At this moment your LoRaWAN gateway should be up and running. Check on the TTN or TTS console if it shows the connected status. + + +## Troubleshoothing It's possible that on the TTN Console the gateway appears as Not connected if it's not receiving any LoRa message. Sometimes the websockets connection among the LoRa Gateway and the server can get broken. However a new LoRa package will re-open the websocket between the Gateway and TTN or TTI. This issue should be solved with the TTN v3. From dde8757e99fedf0a809ab18f6df9831e99c7942e Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Mon, 1 Feb 2021 23:48:53 +0100 Subject: [PATCH 39/88] Update balena.yml --- balena.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/balena.yml b/balena.yml index a86017de..54e2da1b 100644 --- a/balena.yml +++ b/balena.yml @@ -1,14 +1,16 @@ -version: "2" -slug: "balena-basicstation" -name: "TTN basicstation Gateway" +name: "TTN basicstation Gateway V3 and V2" +description: "Deploys a TTN or The Things Stack LoRaWAN gateway with Basics Station Packet Forward protocol. It runs on a Raspberry Pi or Fin with a RAK2245 and 2287 concentrators." type: "sw.application" assets: - - url: "https://github.com/balenalabs/basicstation" - name: "repository" - - url: "https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png" - name: "logo" + repository: + type: "blob.asset" + data: + url: "https://github.com/balenalabs/basicstation" + logo: + type: "blob.asset" + data: + url: "https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png" data: - description: "Deploys a TTN LoRaWAN gateway with Basics Station Packet Forward protocol. It runs on a Raspberry Pi or Fin with a RAK2245 and 2287 concentrators." applicationEnvironmentVariables: - GW_GPS: false - GW_RESET_PIN: 11 @@ -16,7 +18,8 @@ data: - MODEL: RAK2245 - GW_ID: 0 - GW_KEY: 0 - defaultDeviceType: "raspberrypi3" + - TC_KEY: 0 + defaultDeviceType: "raspberry-pi3" supportedDeviceTypes: - "raspberrypi3" - "raspberrypi3-64" From fe17f2c0c36742ff1aaca0f4513ab4c45049e2a8 Mon Sep 17 00:00:00 2001 From: Severin Schols Date: Tue, 2 Feb 2021 00:41:39 +0100 Subject: [PATCH 40/88] Reset color after warning to not mess up shell --- start.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/start.sh b/start.sh index 5881d271..f55c5121 100644 --- a/start.sh +++ b/start.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env bash TAG_KEY="EUI" TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g') @@ -20,7 +20,7 @@ TAG=$(curl -sX POST \ if [ -z ${MODEL} ] ; then - echo -e "\033[91mWARNING: MODEL variable not set.\n Set the model of the gateway you are using." + echo -e "\033[91mWARNING: MODEL variable not set.\n Set the model of the gateway you are using.\033[0m" balena-idle else echo "Using MODEL: $MODEL" @@ -31,6 +31,4 @@ if [ -z ${MODEL} ] ; if [ $MODEL = "RAK2287" ];then ./start_rak2287.sh fi -fi - - +fi From 3d66301630944ef14f1a8d347d361673522fb4f5 Mon Sep 17 00:00:00 2001 From: Severin Schols Date: Tue, 2 Feb 2021 00:43:14 +0100 Subject: [PATCH 41/88] There are no defaults on the MODEL variable, it has to be set --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ce906631..1ccfa661 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # LoRa Basics™ Station using balena.io with RAK2245 or RAK 2287 concentrators -This project deploys a LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 and RAK2287 concentrator with a Pi Hat. +This project deploys a LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 and RAK2287 concentrator with a Pi Hat. ## Introduction @@ -85,7 +85,7 @@ Copy the result and you are ready to register your gateway with this EUI. ### Configure your The Things Network gateway -1. Sign up at [The Things Network console](https://console.thethingsnetwork.org/). +1. Sign up at [The Things Network console](https://console.thethingsnetwork.org/). 2. Click Gateways button. 3. Click the "Register gateway" link. 4. Check “I’m using the legacy packet forwarder” checkbox. @@ -96,7 +96,7 @@ Copy the result and you are ready to register your gateway with this EUI. ### Configure your The Things Stack gateway (The Things Conference 2021) -1. Sign up at [The Things Stack console](https://ttc.eu1.cloud.thethings.industries/console/). +1. Sign up at [The Things Stack console](https://ttc.eu1.cloud.thethings.industries/console/). 2. Click "Go to Gateways" icon. 3. Click the "Add gateway" button. 4. Introduce the data for the gateway. @@ -128,9 +128,9 @@ Variable Name | Value | Description | Default **`GW_GPS`** | `STRING` | Enables GPS | true or false **`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) -**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 +**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` -**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | ```RAK2245``` +**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | #### The Things Stack Variables @@ -142,9 +142,9 @@ Variable Name | Value | Description | Default ------------ | ------------- | ------------- | ------------- **`GW_GPS`** | `STRING` | Enables GPS | true or false **`TC_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) -**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 +**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`TC_URI`** | `STRING` | Gateway Server address. If you are in the EU region use ```wss://ttc.eu1.cloud.thethings.industries:8887``` -**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | ```RAK2245``` +**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | @@ -161,4 +161,3 @@ It's possible that on the TTN Console the gateway appears as Not connected if it - This is an adaptation of the [Semtech Basics Station repository](https://github.com/lorabasics/basicstation). Documentation [here](https://doc.sm.tc/station). - This is in part working thanks of the work of Jose Marcelino from RAK Wireless and Marc Pous from balena.io. - This is in part based on excellent work done by Rahul Thakoor from the Balena.io Hardware Hackers team. - From 5b20b3fd5a4c8cc58c3f6f42816498dae320f325 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 2 Feb 2021 19:36:01 +0100 Subject: [PATCH 42/88] Introducing iC880a model compatibility Testing with Severin --- start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.sh b/start.sh index f55c5121..d9184ccd 100644 --- a/start.sh +++ b/start.sh @@ -24,7 +24,7 @@ if [ -z ${MODEL} ] ; balena-idle else echo "Using MODEL: $MODEL" - if [ $MODEL = "RAK2245" ];then + if [ $MODEL = "RAK2245" ] | [$MODEL = "iC880a"];then ./start_rak2245.sh fi From e6bcfaac4a56653623ab635cf6d5387263d96b52 Mon Sep 17 00:00:00 2001 From: Jose Marcelino Date: Wed, 3 Feb 2021 21:49:57 +0000 Subject: [PATCH 43/88] Fix start.sh Fix comparision issue from previous merge --- start.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start.sh b/start.sh index d9184ccd..0f6faf9d 100644 --- a/start.sh +++ b/start.sh @@ -24,11 +24,11 @@ if [ -z ${MODEL} ] ; balena-idle else echo "Using MODEL: $MODEL" - if [ $MODEL = "RAK2245" ] | [$MODEL = "iC880a"];then + if [ "$MODEL" = "RAK2245" ] || [ "$MODEL" = "iC880a" ];then ./start_rak2245.sh fi - if [ $MODEL = "RAK2287" ];then + if [ "$MODEL" = "RAK2287" ];then ./start_rak2287.sh fi fi From 36ac979d1d8afb32c9b115e5c9abcb2c750d957d Mon Sep 17 00:00:00 2001 From: Rony Vargas Date: Wed, 3 Feb 2021 19:03:18 -0500 Subject: [PATCH 44/88] Update TC_TRUST uri --- start_rak2245.sh | 2 +- start_rak2287.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/start_rak2245.sh b/start_rak2245.sh index 92a98cea..8c27be76 100755 --- a/start_rak2245.sh +++ b/start_rak2245.sh @@ -8,7 +8,7 @@ pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 # Default to TTN server TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} +TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} GW_RESET_PIN=${GW_RESET_PIN:-11} diff --git a/start_rak2287.sh b/start_rak2287.sh index b9abf1d3..8fd139bd 100755 --- a/start_rak2287.sh +++ b/start_rak2287.sh @@ -4,7 +4,7 @@ cd examples/corecell # Default to TTN server TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl https://letsencrypt.org/certs/trustid-x3-root.pem.txt)} +TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} # Setup TC files from environment From 1bdcb270b0978a941b3899afbf108556ad799c7e Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 17 Feb 2021 16:02:49 +0100 Subject: [PATCH 45/88] Update concentrators Introduction of iC880a MODEL into the concentrators documentation --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1ccfa661..fa8484a6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# LoRa Basics™ Station using balena.io with RAK2245 or RAK 2287 concentrators +# LoRa Basics™ Station using balena.io with RAK2245, RAK 2287 and IMST iC880a concentrators -This project deploys a LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi or balenaFin with a RAK2245 and RAK2287 concentrator with a Pi Hat. +This project deploys a LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with a RAK2245, RAK2287 and IMST iC880a LoRa concentrators. ## Introduction @@ -24,6 +24,10 @@ The Basics Station protocol enables the LoRa gateways with a reliable and secure or +* [IMST iC880a](https://shop.imst.de/wireless-modules/lora-products/8/ic880a-spi-lorawan-concentrator-868-mhz) + +or + * [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) ### Software @@ -60,7 +64,7 @@ If you are a balena CLI expert, feel free to use balena CLI. ### Define your MODEL -In case that your LoRa concentrator is a ```RAK2287```, it's important to change the Device Variable with the correct ```MODEL```. The default ```MODEL``` on the balena Application is the ```RAK2245```. +In case that your LoRa concentrator is a ```RAK2287``` or ```iC880a```, it's important to change the Device Variable with the correct ```MODEL```. The default ```MODEL``` on the balena Application is the ```RAK2245```. 1. Go to balenaCloud dashboard and get into your LoRa gateway device site. 2. Click "Device Variables" button on the left menu and change the ```MODEL``` variable to ```RAK2287```. @@ -130,7 +134,7 @@ Variable Name | Value | Description | Default **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` -**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | +**`MODEL`** | `STRING` | ```RAK2245``` , ```RAK2287``` or ```iC880a``` | #### The Things Stack Variables @@ -144,7 +148,7 @@ Variable Name | Value | Description | Default **`TC_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) **`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 **`TC_URI`** | `STRING` | Gateway Server address. If you are in the EU region use ```wss://ttc.eu1.cloud.thethings.industries:8887``` -**`MODEL`** | `STRING` | ```RAK2245``` or ```RAK2287``` | +**`MODEL`** | `STRING` | ```RAK2245``` , ```RAK2287``` or ```iC880a``` | From cca54a0e5ff97a8b13e280bb5886af6d3e8a7ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Tue, 23 Feb 2021 21:17:13 +0100 Subject: [PATCH 46/88] Fix GW EUI, TTN requires it to be lowercase --- README.md | 2 +- start.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa8484a6..8c7756c6 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ To get the EUI, copy the TAG of the device which will be generated automatically If that does not work, go to the terminal box and click "Select a target", then “HostOS”. Once you are inside the shell, type: -```cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g' ``` +```cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1fffe\2#g' ``` Copy the result and you are ready to register your gateway with this EUI. diff --git a/start.sh b/start.sh index 0f6faf9d..98708dfd 100644 --- a/start.sh +++ b/start.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash TAG_KEY="EUI" -TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1FFFE\2#g') +TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1fffe\2#g') echo $TTN_EUI From cad7307c581f2a94560a560166d89e5d6b1115ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Tue, 23 Feb 2021 21:17:52 +0100 Subject: [PATCH 47/88] Force basic station service to run even if previous lock file present (-f flag) --- examples/corecell/start-station.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/corecell/start-station.sh b/examples/corecell/start-station.sh index dc28d0ff..0ef69ccf 100755 --- a/examples/corecell/start-station.sh +++ b/examples/corecell/start-station.sh @@ -81,7 +81,7 @@ STATION_BIN="../../build-corecell-$variant/bin/station" if [ -f "$STATION_BIN" ]; then printf "Using variant=$variant, lns_config='$lns_config'\n" printf "$GREEN Starting Station ... $NC\n" - $STATION_BIN -h $lns_config + $STATION_BIN -f -h $lns_config else printf "$RED [ERROR]: Binary not found @ $STATION_BIN $NC\n" fi From 6aa8f44d1cdd66d995c36c62260e6997ddc4430c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Tue, 23 Feb 2021 21:19:10 +0100 Subject: [PATCH 48/88] GW_RESET_PIN and GW_RESET_GPIO variables working for RAK2287 concentrator --- examples/corecell/reset_lgw.sh | 6 +++--- start_rak2287.sh | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/corecell/reset_lgw.sh b/examples/corecell/reset_lgw.sh index d8c9c591..7732c249 100755 --- a/examples/corecell/reset_lgw.sh +++ b/examples/corecell/reset_lgw.sh @@ -11,8 +11,8 @@ # GPIO mapping has to be adapted with HW # -SX1302_RESET_PIN=17 -SX1302_POWER_EN_PIN=18 +SX1302_RESET_PIN=${GW_RESET_GPIO:-17} +SX1302_POWER_EN_PIN=${GW_RESET_GPIO:-18} WAIT_GPIO() { sleep 0.1 @@ -67,4 +67,4 @@ case "$1" in ;; esac -exit 0 \ No newline at end of file +exit 0 diff --git a/start_rak2287.sh b/start_rak2287.sh index 8fd139bd..a788e6a7 100755 --- a/start_rak2287.sh +++ b/start_rak2287.sh @@ -6,6 +6,12 @@ cd examples/corecell TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} +# declare map of hardware pins to GPIO on Raspberry Pi +declare -a pinToGPIO +pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) +GW_RESET_PIN=${GW_RESET_PIN:-11} +GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} + # Setup TC files from environment echo "$TC_URI" > ./lns-ttn/tc.uri @@ -15,6 +21,8 @@ if [ ! -z ${TC_KEY} ]; then echo "Authorization: Bearer $TC_KEY" | perl -p -e 's/\r\n|\n|\r/\r\n/g' > ./lns-ttn/tc.key fi +# Set other environment variables +export GW_RESET_GPIO=$GW_RESET_GPIO ./start-station.sh -l ./lns-ttn From 20e280507b0e110cf755a5ad0038641b2b02fc48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Tue, 23 Feb 2021 21:20:25 +0100 Subject: [PATCH 49/88] Fixed regression in TTNv2 certificate request. New TTN_STACK_VERSION variable to auto-configure TTNv2 or TTS --- start_rak2245.sh | 32 +++++++++++++++++++++----------- start_rak2287.sh | 23 ++++++++++++++++++----- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/start_rak2245.sh b/start_rak2245.sh index 8c27be76..70430ab7 100755 --- a/start_rak2245.sh +++ b/start_rak2245.sh @@ -1,29 +1,39 @@ #!/usr/bin/env bash -cd examples/live-s2.sm.tc +# Defaults to TTN server v2 +TTN_STACK_VERSION=${TTN_STACK_VERSION:-2} +if [ $TTN_STACK_VERSION -eq 2 ]; then + TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} + TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/trustid-x3-root.pem.txt"))} +elif [ $TTN_STACK_VERSION -eq 3 ]; then + TC_URI=${TC_URI:-"wss://eu1.cloud.thethings.network:8887"} + TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} +else + echo -e "\033[91mERROR: Wrong TTN_STACK_VERSION value, should be either 2 o 3.\033[0m" + balena-idle +fi + +# Check configuration +if [ $TC_URI = "" ] || [ $TC_TRUST == "" ]; then + echo -e "\033[91mERROR: Missing configuration, define either TTN_STACK_VERSION or TC_URI and TC_TRUST.\033[0m" + balena-idle +fi # declare map of hardware pins to GPIO on Raspberry Pi declare -a pinToGPIO pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) - -# Default to TTN server -TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} - - GW_RESET_PIN=${GW_RESET_PIN:-11} GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} +cd examples/live-s2.sm.tc + # Setup TC files from environment -echo $TC_URI > tc.uri +echo "$TC_URI" > tc.uri echo "$TC_TRUST" > tc.trust - if [ ! -z ${TC_KEY} ]; then echo "Authorization: Bearer $TC_KEY" | perl -p -e 's/\r\n|\n|\r/\r\n/g' > tc.key fi - - # Reset gateway echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" echo $GW_RESET_GPIO > /sys/class/gpio/export diff --git a/start_rak2287.sh b/start_rak2287.sh index a788e6a7..1f16b72d 100755 --- a/start_rak2287.sh +++ b/start_rak2287.sh @@ -1,10 +1,23 @@ #!/usr/bin/env bash -cd examples/corecell +# Defaults to TTN server v2 +TTN_STACK_VERSION=${TTN_STACK_VERSION:-2} +if [ $TTN_STACK_VERSION -eq 2 ]; then + TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} + TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/trustid-x3-root.pem.txt"))} +elif [ $TTN_STACK_VERSION -eq 3 ]; then + TC_URI=${TC_URI:-"wss://eu1.cloud.thethings.network:8887"} + TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} +else + echo -e "\033[91mERROR: Wrong TTN_STACK_VERSION value, should be either 2 o 3.\033[0m" + balena-idle +fi -# Default to TTN server -TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} -TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} +# Check configuration +if [ $TC_URI = "" ] || [ $TC_TRUST == "" ]; then + echo -e "\033[91mERROR: Missing configuration, define either TTN_STACK_VERSION or TC_URI and TC_TRUST.\033[0m" + balena-idle +fi # declare map of hardware pins to GPIO on Raspberry Pi declare -a pinToGPIO @@ -12,11 +25,11 @@ pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 GW_RESET_PIN=${GW_RESET_PIN:-11} GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} +cd examples/corecell # Setup TC files from environment echo "$TC_URI" > ./lns-ttn/tc.uri echo "$TC_TRUST" > ./lns-ttn/tc.trust - if [ ! -z ${TC_KEY} ]; then echo "Authorization: Bearer $TC_KEY" | perl -p -e 's/\r\n|\n|\r/\r\n/g' > ./lns-ttn/tc.key fi From 73ba8041dc96e1dedccbdc5ad18998b2c6c3701a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Tue, 23 Feb 2021 21:22:12 +0100 Subject: [PATCH 50/88] Update README.md --- README.md | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8c7756c6..b04d2c67 100644 --- a/README.md +++ b/README.md @@ -120,35 +120,45 @@ Once successfully registered: 1. Go to balenaCloud dashboard and get into your LoRa gateway device site. 2. Click "Device Variables" button on the left menu and add these variables. -#### The Things Network Variables +Alternativelly, you can also set any of them at application level if you want it to apply to all devices in you application. + + +#### Common Variables + +Variable Name | Value | Description | Default +------------ | ------------- | ------------- | ------------- +**`GW_GPS`** | `STRING` | Enables GPS | true or false +**`GW_RESET_PIN`** | `INT` | Pin number that resets (Raspberry Pi header number) | 11 +**`GW_RESET_GPIO`** | `INT` | GPIO number that resets (Broadcom pin number, if not defined, it's calculated based on the GW_RESET_PIN) | 17 +**`TTN_STACK_VERSION`** | `INT` | If using TTN, version of the stack. It can be either 2 (TTNv2) or 3 (TTS) | 2 +**`TC_URI`** | `STRING` | basics station TC URI to get connected. | ```wss://lns.eu.thethings.network:443``` +**`TC_TRUST`** | `STRING` | Certificate for the server | Automatically retrieved from LetsEncryt based on the `TTN_STACK_VERSION` value +**`MODEL`** | `STRING` | ```RAK2245``` , ```RAK2287``` or ```iC880a``` | + + +#### The Things Network (TTNv2) Specific Variables Remember to copy the The Things Network gateway KEY and ID to configure your board variables on balenaCloud. The `GW_ID`and `GW_KEY` variables have been generated automatically when the Application has been created with the Deploy with Balena button. Replace the values with the KEY and ID from the TTN console. +The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://lns.eu.thethings.network:443``` if you set `TTN_STACK_VERSION` to 2. If your region is not EU you still have to set `TC_URI`. Use ```wss://lns.{eu-us-in-au}.thethings.network:443```. Variable Name | Value | Description | Default ------------ | ------------- | ------------- | ------------- -**`GW_GPS`** | `STRING` | Enables GPS | true or false **`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) **`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) -**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 -**`TC_URI`** | `STRING` | basics station TC URI to get connected. If you are in the EU region use ```wss://lns.{eu-us-in-au}.thethings.network:443``` | ```wss://lns.eu.thethings.network:443``` -**`MODEL`** | `STRING` | ```RAK2245``` , ```RAK2287``` or ```iC880a``` | -#### The Things Stack Variables +#### The Things Stack (TTS) Specific Variables Remember to generate an API Key and copy it. It will be the ```TC_KEY```. +The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://eu1.cloud.thethings.network:8887``` if you set `TTN_STACK_VERSION` to 3. If your region is not EU you still have to set `TC_URI`. At the moment there is only one server avalable (```eu1```). Variable Name | Value | Description | Default ------------ | ------------- | ------------- | ------------- -**`GW_GPS`** | `STRING` | Enables GPS | true or false **`TC_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) -**`GW_RESET_PIN`** | `STRING` | Pin number that resets | 11 -**`TC_URI`** | `STRING` | Gateway Server address. If you are in the EU region use ```wss://ttc.eu1.cloud.thethings.industries:8887``` -**`MODEL`** | `STRING` | ```RAK2245``` , ```RAK2287``` or ```iC880a``` | @@ -159,6 +169,17 @@ At this moment your LoRaWAN gateway should be up and running. Check on the TTN o It's possible that on the TTN Console the gateway appears as Not connected if it's not receiving any LoRa message. Sometimes the websockets connection among the LoRa Gateway and the server can get broken. However a new LoRa package will re-open the websocket between the Gateway and TTN or TTI. This issue should be solved with the TTN v3. +## TTNv2 to TTS migration + +Initial state: one of more devices connected to TTNv2 stack (The Things Network). + +Proposed procedure: + +1. Create the gateways at TTS using the very same Gateway ID (Gateway EUI) +2. Create a `TC_KEY` variable on each device sith the TTN Gateway Key pasted from the TTI console. +3. Set the `TTN_STACK_VERSION` variable to 3, either at application level or per device + +Now you can move them from TTS to TTNv2 back and forth (using the `TTN_STACK_VERSION` variable) as you wish as long as the gateways are defined on both platforms and the `TC_KEY` and `GW_KEY` do not change. ## Attribution From dd9b61057ddcf425d3794aded751ea78eab10792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Wed, 24 Feb 2021 14:25:27 +0100 Subject: [PATCH 51/88] Added TTN_REGION variable. Refactor common parts --- README.md | 5 +++-- start.sh | 2 +- start_common.sh | 29 +++++++++++++++++++++++++++++ start_rak2245.sh | 27 +++------------------------ start_rak2287.sh | 27 +++------------------------ 5 files changed, 39 insertions(+), 51 deletions(-) create mode 100644 start_common.sh diff --git a/README.md b/README.md index b04d2c67..7bf14f52 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,7 @@ Variable Name | Value | Description | Default **`GW_RESET_PIN`** | `INT` | Pin number that resets (Raspberry Pi header number) | 11 **`GW_RESET_GPIO`** | `INT` | GPIO number that resets (Broadcom pin number, if not defined, it's calculated based on the GW_RESET_PIN) | 17 **`TTN_STACK_VERSION`** | `INT` | If using TTN, version of the stack. It can be either 2 (TTNv2) or 3 (TTS) | 2 +**`TTN_REGION`** | `STRING` | Region of the TTN server to use | ```eu``` when using TTNv2, ```eu1``` for TTS **`TC_URI`** | `STRING` | basics station TC URI to get connected. | ```wss://lns.eu.thethings.network:443``` **`TC_TRUST`** | `STRING` | Certificate for the server | Automatically retrieved from LetsEncryt based on the `TTN_STACK_VERSION` value **`MODEL`** | `STRING` | ```RAK2245``` , ```RAK2287``` or ```iC880a``` | @@ -142,7 +143,7 @@ Remember to copy the The Things Network gateway KEY and ID to configure your boa The `GW_ID`and `GW_KEY` variables have been generated automatically when the Application has been created with the Deploy with Balena button. Replace the values with the KEY and ID from the TTN console. -The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://lns.eu.thethings.network:443``` if you set `TTN_STACK_VERSION` to 2. If your region is not EU you still have to set `TC_URI`. Use ```wss://lns.{eu-us-in-au}.thethings.network:443```. +The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://lns.eu.thethings.network:443``` if you set `TTN_STACK_VERSION` to 2. If your region is not EU you can set it using ```TTN_REGION```, Possible values are ```eu```, ```us```, ```in``` and ```au```. Variable Name | Value | Description | Default ------------ | ------------- | ------------- | ------------- @@ -154,7 +155,7 @@ Variable Name | Value | Description | Default Remember to generate an API Key and copy it. It will be the ```TC_KEY```. -The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://eu1.cloud.thethings.network:8887``` if you set `TTN_STACK_VERSION` to 3. If your region is not EU you still have to set `TC_URI`. At the moment there is only one server avalable (```eu1```). +The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://eu1.cloud.thethings.network:8887``` if you set `TTN_STACK_VERSION` to 3.If your region is not EU you can set it using ```TTN_REGION```. At the moment there is only one server avalable is ```eu1```. Variable Name | Value | Description | Default ------------ | ------------- | ------------- | ------------- diff --git a/start.sh b/start.sh index 98708dfd..a0f7d90c 100644 --- a/start.sh +++ b/start.sh @@ -3,7 +3,7 @@ TAG_KEY="EUI" TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1fffe\2#g') -echo $TTN_EUI +echo "Gateway EUI: $TTN_EUI" ID=$(curl -sX GET "https://api.balena-cloud.com/v5/device?\$filter=uuid%20eq%20'$BALENA_DEVICE_UUID'" \ -H "Content-Type: application/json" \ diff --git a/start_common.sh b/start_common.sh new file mode 100644 index 00000000..89ed8672 --- /dev/null +++ b/start_common.sh @@ -0,0 +1,29 @@ +# Defaults to TTN server v2, EU region +TTN_STACK_VERSION=${TTN_STACK_VERSION:-2} +if [ $TTN_STACK_VERSION -eq 2 ]; then + TTN_REGION=${TTN_REGION:-"eu"} + TC_URI=${TC_URI:-"wss://lns.${TTN_REGION}.thethings.network:443"} + TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/trustid-x3-root.pem.txt"))} +elif [ $TTN_STACK_VERSION -eq 3 ]; then + TTN_REGION=${TTN_REGION:-"eu1"} + TC_URI=${TC_URI:-"wss://${TTN_REGION}.cloud.thethings.network:8887"} + TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} +else + echo -e "\033[91mERROR: Wrong TTN_STACK_VERSION value, should be either 2 o 3.\033[0m" + balena-idle +fi + +# Check configuration +if [ "$TC_URI" == "" ] || [ "$TC_TRUST" == "" ] +then + echo -e "\033[91mERROR: Missing configuration, define either TTN_STACK_VERSION or TC_URI and TC_TRUST.\033[0m" + balena-idle +fi + +echo "Server: $TC_URI" + +# declare map of hardware pins to GPIO on Raspberry Pi +declare -a pinToGPIO +pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) +GW_RESET_PIN=${GW_RESET_PIN:-11} +GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} diff --git a/start_rak2245.sh b/start_rak2245.sh index 70430ab7..7b1d9bad 100755 --- a/start_rak2245.sh +++ b/start_rak2245.sh @@ -1,30 +1,9 @@ #!/usr/bin/env bash -# Defaults to TTN server v2 -TTN_STACK_VERSION=${TTN_STACK_VERSION:-2} -if [ $TTN_STACK_VERSION -eq 2 ]; then - TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} - TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/trustid-x3-root.pem.txt"))} -elif [ $TTN_STACK_VERSION -eq 3 ]; then - TC_URI=${TC_URI:-"wss://eu1.cloud.thethings.network:8887"} - TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} -else - echo -e "\033[91mERROR: Wrong TTN_STACK_VERSION value, should be either 2 o 3.\033[0m" - balena-idle -fi - -# Check configuration -if [ $TC_URI = "" ] || [ $TC_TRUST == "" ]; then - echo -e "\033[91mERROR: Missing configuration, define either TTN_STACK_VERSION or TC_URI and TC_TRUST.\033[0m" - balena-idle -fi - -# declare map of hardware pins to GPIO on Raspberry Pi -declare -a pinToGPIO -pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) -GW_RESET_PIN=${GW_RESET_PIN:-11} -GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} +# Load common variables +source ./start_common.sh +# Change to project folder cd examples/live-s2.sm.tc # Setup TC files from environment diff --git a/start_rak2287.sh b/start_rak2287.sh index 1f16b72d..eebce3a8 100755 --- a/start_rak2287.sh +++ b/start_rak2287.sh @@ -1,30 +1,9 @@ #!/usr/bin/env bash -# Defaults to TTN server v2 -TTN_STACK_VERSION=${TTN_STACK_VERSION:-2} -if [ $TTN_STACK_VERSION -eq 2 ]; then - TC_URI=${TC_URI:-"wss://lns.eu.thethings.network:443"} - TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/trustid-x3-root.pem.txt"))} -elif [ $TTN_STACK_VERSION -eq 3 ]; then - TC_URI=${TC_URI:-"wss://eu1.cloud.thethings.network:8887"} - TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} -else - echo -e "\033[91mERROR: Wrong TTN_STACK_VERSION value, should be either 2 o 3.\033[0m" - balena-idle -fi - -# Check configuration -if [ $TC_URI = "" ] || [ $TC_TRUST == "" ]; then - echo -e "\033[91mERROR: Missing configuration, define either TTN_STACK_VERSION or TC_URI and TC_TRUST.\033[0m" - balena-idle -fi - -# declare map of hardware pins to GPIO on Raspberry Pi -declare -a pinToGPIO -pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) -GW_RESET_PIN=${GW_RESET_PIN:-11} -GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} +# Load common variables +source ./start_common.sh +# Change to project folder cd examples/corecell # Setup TC files from environment From 5c1a058a56c402658ef3de0a749ca33f76c90738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Sun, 7 Mar 2021 18:21:18 +0100 Subject: [PATCH 52/88] Do not idle if service stop, so the container will reboot --- start.sh | 2 ++ start_rak2245.sh | 2 -- start_rak2287.sh | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/start.sh b/start.sh index a0f7d90c..26b46c5c 100644 --- a/start.sh +++ b/start.sh @@ -32,3 +32,5 @@ if [ -z ${MODEL} ] ; ./start_rak2287.sh fi fi + +#balena-idle diff --git a/start_rak2245.sh b/start_rak2245.sh index 7b1d9bad..e8a47617 100755 --- a/start_rak2245.sh +++ b/start_rak2245.sh @@ -23,5 +23,3 @@ echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value echo $GW_RESET_GPIO > /sys/class/gpio/unexport RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station - -balena-idle diff --git a/start_rak2287.sh b/start_rak2287.sh index eebce3a8..8ae61028 100755 --- a/start_rak2287.sh +++ b/start_rak2287.sh @@ -17,5 +17,3 @@ fi export GW_RESET_GPIO=$GW_RESET_GPIO ./start-station.sh -l ./lns-ttn - -balena-idle From 76de94b969c660e2ba1192fc9cb02f1910617027 Mon Sep 17 00:00:00 2001 From: mpous Date: Thu, 11 Mar 2021 11:56:44 +0100 Subject: [PATCH 53/88] V2 to V3 changes --- README.md | 35 ++++++++++++++-------------- balena.yml | 5 +++- logo.png | Bin 48319 -> 68861 bytes start.sh | 11 ++++----- start_rak2245.sh => start_sx1301.sh | 0 start_rak2287.sh => start_sx1302.sh | 0 6 files changed, 27 insertions(+), 24 deletions(-) rename start_rak2245.sh => start_sx1301.sh (100%) rename start_rak2287.sh => start_sx1302.sh (100%) diff --git a/README.md b/README.md index 7bf14f52..f1d01df1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# LoRa Basics™ Station using balena.io with RAK2245, RAK 2287 and IMST iC880a concentrators +# LoRa Basics™ Station using balena.io with sx1301 and sx1302 LoRa concentrators -This project deploys a LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with a RAK2245, RAK2287 and IMST iC880a LoRa concentrators. +This project deploys a LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with a RAK2245, RAK2287 and IMST iC880a LoRa concentrators (sx1301 and sx1302). ## Introduction @@ -19,20 +19,17 @@ The Basics Station protocol enables the LoRa gateways with a reliable and secure #### LoRa Concentrators -* [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) -* [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) +* SX1301 + * [IMST iC880a](https://shop.imst.de/wireless-modules/lora-products/8/ic880a-spi-lorawan-concentrator-868-mhz) + * [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) -or +* SX1302 + * [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) with [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) -* [IMST iC880a](https://shop.imst.de/wireless-modules/lora-products/8/ic880a-spi-lorawan-concentrator-868-mhz) - -or - -* [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) ### Software -* A TTN account ([sign up here](https://console.thethingsnetwork.org)) +* A TTN or The Things Stack V3 account ([sign up here](https://console.thethingsnetwork.org)) or [here](https://ttc.eu1.cloud.thethings.industries/console/) * A balenaCloud account ([sign up here](https://dashboard.balena-cloud.com/)) * [balenaEtcher](https://balena.io/etcher) @@ -64,15 +61,19 @@ If you are a balena CLI expert, feel free to use balena CLI. ### Define your MODEL -In case that your LoRa concentrator is a ```RAK2287``` or ```iC880a```, it's important to change the Device Variable with the correct ```MODEL```. The default ```MODEL``` on the balena Application is the ```RAK2245```. +The model is defined depending on the version of the concentrator: ```SX1301``` or ```SX1302```. In case that your LoRa concentrator is a ```RAK2287``` it is using ```SX1302```. If the concentrator is the ```RAK2245``` or ```iC880a``` it uses the ```SX1301```. It's important to change the balenaCloud Device Variable with the correct ```MODEL```. The default ```MODEL``` on the balena Application is the ```SX1301```. 1. Go to balenaCloud dashboard and get into your LoRa gateway device site. -2. Click "Device Variables" button on the left menu and change the ```MODEL``` variable to ```RAK2287```. +2. Click "Device Variables" button on the left menu and change the ```MODEL``` variable to ```SX1302``` if needed. + +That enables a fleet of LoRa gateways with both (e.g.) ```RAK2245``` and ```RAK2287``` together under the same app. -That enables a fleet of LoRa gateways with both ```RAK2245``` and ```RAK2287``` together under the same app. +### Define your REGION and TTN STACK VERSION -Before starting check the region where you are going to deploy the gateway, de facto configuration is for EU gateways. Change the ```TC_URI```if you are in a different zone than European. +From now it's important to facilitate the ```TTN_STACK_VERSION``` that you are going to use ```2``` (TTN v2) or ```3``` (The Things Stack or TTN V3). The default variable is defined (still) into ```2```(V2). +Before starting, also check the ```TTN_REGION```. It needs to be changed if your region is not Europe. In case you use version 3, the European version is ```eu1```. Check [here](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html) the LoRa frequencies by country. +With these variables ```TTN_REGION``` and ```TTN_STACK_VERSION``` the ```TC_URI``` will be generated automatically. In case that you want to point to another specific TC_URI, feel free to change this Device Variable on the balenaCloud. ### Get the EUI of the LoRa Gateway @@ -134,7 +135,7 @@ Variable Name | Value | Description | Default **`TTN_REGION`** | `STRING` | Region of the TTN server to use | ```eu``` when using TTNv2, ```eu1``` for TTS **`TC_URI`** | `STRING` | basics station TC URI to get connected. | ```wss://lns.eu.thethings.network:443``` **`TC_TRUST`** | `STRING` | Certificate for the server | Automatically retrieved from LetsEncryt based on the `TTN_STACK_VERSION` value -**`MODEL`** | `STRING` | ```RAK2245``` , ```RAK2287``` or ```iC880a``` | +**`MODEL`** | `STRING` | ```SX1301``` or ```SX1302``` | ```SX1301``` #### The Things Network (TTNv2) Specific Variables @@ -185,5 +186,5 @@ Now you can move them from TTS to TTNv2 back and forth (using the `TTN_STACK_VER ## Attribution - This is an adaptation of the [Semtech Basics Station repository](https://github.com/lorabasics/basicstation). Documentation [here](https://doc.sm.tc/station). -- This is in part working thanks of the work of Jose Marcelino from RAK Wireless and Marc Pous from balena.io. +- This is in part working thanks of the work of Jose Marcelino from RAK Wireless, Xose PĂ©rez from Allwize and Marc Pous from balena.io. - This is in part based on excellent work done by Rahul Thakoor from the Balena.io Hardware Hackers team. diff --git a/balena.yml b/balena.yml index 54e2da1b..4abad7de 100644 --- a/balena.yml +++ b/balena.yml @@ -14,8 +14,11 @@ data: applicationEnvironmentVariables: - GW_GPS: false - GW_RESET_PIN: 11 + - GW_RESET_GPIO: 17 - TC_URI: wss://lns.eu.thethings.network:443 - - MODEL: RAK2245 + - MODEL: SX1301 + - TTN_STACK_VERSION: 2 + - TTN_REGION: eu - GW_ID: 0 - GW_KEY: 0 - TC_KEY: 0 diff --git a/logo.png b/logo.png index e4f7a19b7770a278d692479c5e98aaaa861347e8..9e310d016d05555979b2e190e9f8db65094bc068 100644 GIT binary patch literal 68861 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

b{vA5N64NKchbWOOu$A_Nd7v4&QK& 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%0Dnu$zPEiqgZfSCF_CkmVsRd{{=U~4 zMXH^=g?;7vO6thDw+UVWA&6@r=NbeT6swZ|Y+Cw}3lBFy9D;Rw4XUBLKk{5Pm*;xR zj%d;K1&XNf>PDJN1(5JoPnL|~{n$_b&ArVyb2VKH>&Z!mDjU{krx^+kZ2PCW?ARGY zvPJm7tzw$$JxsqEW9O!?np=h11VZCyo=Yz!lWmiJZKaX@N-dhQO;-IT3Gd$c`9hIa zg;&5VJkWlD<*ZKnK^=$MPGHuST9sGjX<~t3JA-usC@EF6V0wqP^txu~N(5q+i=<|` za10D-EqA|&kKLae@8k$0jTNWhUkl9cc>k{*J124=Owav=dl{lH48rD5L75gk(h^kn z*q0&gVnYVMZC*J!$m{Hd8$#f{JI*lvga&d(9VRqppMepCfj?KQY=XYK{Y3e|5PCV6 zqn}Dg`J-2U(e#$}*6qSXJA}D z$Q9|{w3u9(dMhAb1%_)lah@s4S5{3DPfTjXrR?(5AAS>TS5j$fbDl)9>1x$Ex^B>^ z5drn?pm#ELy9ml*7G1O!0Q_>OGJ_w-21jbYSKRx(M zQiUo0ln=l_;qeHvEcc4FNW9NeJNM4jeiho-%H`h9y~*FAy=qSzl-(LP4)q3(T z7XV+6)P2&3J0hjhwqHF?gAr}dFCJIK^%|IC>h*g}&!2^3r84(XxuAtFH?S_LWxK2U zeqlqZgN`lSn##KL^_WCzO_HwL{L&78oQga-_DaS$Z?@<^C!SVp+hHVgkqq?b4`5qN z^rU<%@vpi80p9@br7|xxS-eboN8+Zz+dv4z4@YeUCTZ{m6&_?^^If3cfBx+0wdT0P{D~R})D>IpxW^j^}h0WL* zXVGG{TDe!-$qiS4;B}mTLL5GREQtvq}9x+5fK2f_jbLi3awJmQ{P z_4Az9exL;WsE|$~a2(KLDE3ex_$LJ7!PuN6Z#tvkyC$`6kX&t^bAN<+LfG353N|FX zcVQ){^TAJ!@TVe^rxLgMa)K(4Q;kb=_wlvX5hdhNxmgnA!N)sN2q|mG<$ueZy~H!( zyZR10DPcr2dmBjov<;|6TR(C@uI~K)Kq04|RHLrOc>>%|*3Aw~^6@zlFvAU#H#Yxo zfX6`Rkn8O_Uw)QLHz46IvTdCY((F_kZ=>5yXUwT?s&i8@s0TNJ^uS;ua2oJ>wYT!v zL>@66w5VS9#N`xOQ(v&xjG?@9al|$6H4E%O z6@nFeD;Ura;N2gAg}=~Nc@W@>`+nh2g}_pJ`KtIQB)M1QrMDD(lkcVV+?NAyk{R}; zO%sEm`@&3KQ*u8U>%~rh4tw`R0{YICnAtfAfAfXHrwdhjD7D3)Um(@+3vr{KnQn#h zAx=m>I2C_d4tP^6@RcOpp|61Iz&e&F(@lZwlSbtuJPh>nsJobAvG{nzHEXYTbXoJ; zN`s&O;6V=VS+~D#KN?K_6U7tIoHxR5Jo9-SHUaRi#x{&Pa~N;A8xetff&QgZFg-vF z0W^5%e<}Jnv~K^E5f6fv^AVTrSoqooP5NIpg8ZkEl`Bh<92>X5HPEmzi zbxMwJSK0Y>&ALmd-jY8Sz)(3Lf&MP@ z{Pr*e5zm;6RBwpx1mC;O%ua9{?kwPQiM?^k0Tuaqwa0MO7ki0xP9IZcHY*mhgRJv* zSeV^93l|)AML;RCVX=!*U)>=?2@Pfaa9O{oY$aJl)Uj}`%Bxj}&@-FOsLSRn| zZ|T?o{z+iOQalri`B{&~`49^vesAS`HA328fqw)i za^c;B1+?j5n+&qFirV$a=rlG*sp9ZtQM%4{dI894c~YbJnf17bWo==Jln`F~Fk5%WWg>7X{YD{YR;dMSwDAZom#G2g*M9BHp2|+eU9C@m zDQ;z8gMwC9K>zW3%%FgcyC+&3-=cA0T&hiqB~nJfE5->%GAe?UT6IKoK0`~IqsE3e zS>LFZ0K{0q^=ve*4+_4X?WsE)t8&hTQ zG-9B6Ck|LtoUy0|jK2*PAe?ym5n!6QKz}$*uavdOC5$xU=^GuLyC>w`pk5RoAI%5H zXr;!u;TXjV@QM`!v)<-h26?m)z&j4$aut`)tFQgME%p&`J%NYE3I#~+NY`1D* zire_XYH7PYAN*p0>r=2Wq2u8pcF(i&F2Oh#AXB~i#4;hd5!2IvWKYGF}?k;is z96nd|8UNa~(|KWW`wDdw&nr&LPD4+zt{c3ngEfeUeUt!aXYh*y382JxiRF;saSgZ+ z$@r)2@3;Bc`*D-k|JnX0Q60d<8>>V3dJTqLkJt+Ax@}JBt1!;CHBQL;g2`d*(JkdU zyGn1@;hla7xVvmV_~=Pt^TH#JsE4(Gva6ybf!vkG3Asx7?-MN;UTXUvBwm7#DzH{A zb(?xlM-#RLwyg;q-JhISZ3pF_7%kLt)#H*v)zZon=E|P=#do19w^$ne>J8u`$L6GU z=C?$EdW#eHFz&|&bsTRvkZ=M(3o4Q)z*r?l@qB_nQB5%ERsNSMVRUA5+*FCrp288b z3GxC@d71>MWL!%<_X0m<1oOpT${z)SID7Y#uHA7tJ&(rdp3Y17r*kU(_jlG6ARpHq1{M1~1Xo7B!9iw5{!I!o(#5}POUZ@q+IeOGS|yB@&;S-zJCHZbwVpVm8yw@4bJ`e9CKmf1bVl1N1{#!w+J)qn=UASJw{qdu zbPp)G0rXE99cM3gH6IPWiqN!xPO8GWps&}y$BMVGwNA@1%0d;22qxlzNYlv^Mnd#H zOHgd?1FWdZ5fgQ9yF7m!WE8)**#?U8Wut~>mAnE#XEeXP7_{Ul6u9%23uWTgOTD>+ z7GWw42?sIped*`OKsPjh|N4~MpX?7S2Rf<+9QR2-cbr#Ei!kRil<+70U}ZT6a*|){ z|IJB~A0cx63x2&2OHjRN@)}!E$gh?PYvW}dVKMb;OmD35%@Ixc&U<z>BYeL%dU%P-;6Kfhr}#SlGq$&cK-k|vgs4M8e5>r@E`(fRrM6e*pnHJs4scz*=R zT@PN{vFg*4Ef@zkkhfxgrTyDf0BAP;f<$$BOvjAh2eBzkOxwGnW2jy%R9@CD4T}#8 zez%+}O<{Zg<{H0hgqP#0;d%q#gXe>Al0n$c46_(IyDQ>_6DKkqs;-l^QLoj8o=i%3 zk3nSo$?HzUC%k{Hk$5Iyz-uW)0@+ol=w-e6ngtHUeH0t>gmx3cpAeGLv8iYuU_o02Tv_UxdAuX z;sBKf@0z=s|Fjy8z#Z5xb4`hV;f^eftkHuK7}t+xKAhwhZBno(v5LF9H5c83U~MZV zAYHG=RUMbc!Du<_IgIlOo`?270gQQ zXx3(M6hV$s35Giwjy2xW(>qV8d)EIkR<&*;6^ZkIH63*A+pCGYy{q)`*ei7%7nj8W zaE1Z=FK-!P|5~xKEM^4O_HgJ7A*h`dx6ygs3P>2d@@_8RMjMG+n^pVcPiOcW0|Xfh z_jcei<@?vg?wt4(X`7Yeg1&T)^LY7jh}dYRG1bV$%iCS`ox_y7U3F~09jW~Ok-k5P zIG7QlYiTS@(4ipur!&ie#p$ugv!av3_`kw;AbSj0B*k5|e*`Z;-|;CVl^6WbnF81V4YaJ{Cl#yc>h#2b-%vd6 z`UhUbb}_Myda}`aABFeV-R{40dCtpkBwSWwCmEKZ09Nv|S)5vui2V2#u)6HF>SHDep5)mzvcPno-4jaH>}U$V;8%4yqlmN z8IR!Q#UyEj3tkID^b}aK_l_Wf&nuVs7KtZ8zee}BrgX#rs*}F#q|8=yXMx?YLOMa=B5`zD~n9aP7N2fZIn2A*(`C) zI-Uiw__}qT(<+MJjN@)U0e{q^U-l1BobvQ0-x?l!x;lVm5v0{rAW` zl=Odo5Y*9oR+I}HNoYK?^Kl3VL=qVvq+@_?E-nuNEyX;H$xTD>{>JY`!RreQW>v2^ z3NIm&t_+XX2`$5HLso(;o~$BNq*CoqPEuval-r&Fky-etqBa1k|L5ed5`hK9{UqX= z?=YUM*I``f1uI6X7_`SD=x2qxVPY%`?hwT|^WU$GlUSkA-*PegYwo&CU-%$ib(&rK zWE}Z%Std2i_E$cBqt7U@X^%I?nhI1No>jiWm{xNf=nEkcI?Cl4gbygnn8z18@}0N)uET7T|ijyb6(l>Cc(oQMBp-GyDx+d zoubwkBAAcZE^7K18u2>P(%rgPPT4KoI&X$URo-!LxZ>U9dA7T7{xl3XA<@B;2mEA5 zM92;RG-SiP$wDZODMHKBC?A|3*04(Y9o#qPW#e;?G*jll&3%;FZ0jA^h3c}L#Y^E` zCfCUF%0gmpl#Yj}XOZxyEz5?ckRQTO28Y(tue4z)iU(}7(p4c{sGs~LX^7e*G6-BE zkJ4hfA@^!^-M-k&C)BG^IqqS+XlcxrY!5*^OMtUZODecSUL7O>XghA$_O0RoG#C}T zYl3i}MZvBDfGn?z10c&I0!NGMjz6J|9fUsl^+l~lgs}ML89k!%m*qmg0nvG5Uba}i z)@tC%7Kmfp^_67RoT}p)KRkCfoE7C-u*6#6)fi>&)J{7M5sk?m^K}sjKA>=ynlgwI zm42mE#n$M#>m^H&&|nJ+=iv^QEu^OfG~sxZKpP0CKS+068Q&yy;d}nYF8=Ob01u#W zXTRlq9KNl^_Y+|KnZ^#n0Ut!YPrZACc(JC(8Ap}KU5I-i{oNgBaK&#-;VxK6+{kj_ z^n4jMZoqj?)q6}_Pd0y#80`e=ckzjjQ_*t9%|*G@HX5o30f#bRljP64V}%aP`#ka; z*ernG0dtERfk4ngukBt`@&S`$>vZnR*J!7xn zYxm<}dwA48gW3@(z)o*s)%CZ?y!ZfMUXNbs^LY+`pH8&&KiD3Oy3`2bBUnQt2srnS>I_J@kgWz9Vo0cymdT|`{n zu^;XiHBJ!m#=iM9C9hko0;=IZ$VsAN$ieuYI4Ic;KD~Ea1ZDmyzNbcTa}% zBubp}Drlx$%~y5S-hW^)%1_8_axKa-W>O@ zf3GaY%x~a4h(C1pH?$QQe#p&D~m*F0AuY`<%}ierz* zMkx|+pr-ekm?Gtb;`b#!)*4+YNb0BnPas?P)uiy(BYKD&uzeop25`LkV%Fjp+FdNN zb7`=1j8FW7z(s7kN=FF3_c+vV`;|3LqamDX82N0NNVSDM!sCR9A{+mhB=HCB;TcME z@K!3~{v9C95*J<<;sj~!xNZP7I(N{rCs#ZG z>_RuGjv}*SApf8=2PL+sX?5BbgRpX)8rvaG<65vWD|4OGmUC@ZM((@1)el~&)YrOH8X`#WvvX?A>GZZ$n>4okiT2Kb zpDr*sZgp)DhwJYCSqTlLWK`76RBWNMD`UN4;sB>8DF`72?xB<$JVo&RBno+A?gW%! zDGr68#D12q`RHlPja#8YT9LjQZT6=V*Ac~M(=t9bwXHVE#^H7&?n6sU@60?7CB3>b z2_$vje<>jBKp#h(pKc1E?1m@iZM>?^5tpWa9W)hWWAZrJph7MrgP zDp;GsRoxV%XjA{lXWNEop4k{*PjuxGhwIy%4x14#Db!RY^V+BVoMX)bHq+QLz>Bf7 z)GwA#w|(f@Q1e96>M;prt$jS2hWAG#``qaqgC;Gs65n#xH>TVRHrI}(sy`bk@pTN^ zzbIQrSlyxa0|&KDmgZ$-m@V1tZsfM#oo6>P`Z8hTwV#0CrL=A4lRx*wztoE>k3gnx z_t)9%VR`y7^(*eSEF7WJGOx4Pbh$MT)1DmN%-h@>QzJ=GWK$DhPAdvrWpWWZ}9@mVQ?Mn9hls2VE2L**_M?RiaVVrbe*VTFBVtHU%jEps-k7nY{;t>pmC{XXC^^IKQr{FN>L!Dp#9cw3lWTB! z%T}ji02y{kP9pWfUDoU%qpsXfWuwnY2U!+L));>CDg-?*OmV@o-H;w!| zXTDQKtOh?oh9cePG3BZ~gkS^%*WlqB1B|kz5Q;8>eS2lp&bQEWKjc9uMAqlSjo;xN7N>i6=S1=F$OOMBvJ z_NVsXiO~6TYK{BvS(R_NmH#ptW%1oWmuZ#qV7@LUFi*H>Jp&UiF$$hN{0ijqAN0?Tt{#yYChvxK zdsjfHEn|69VM%Mk%$e@ZwMn)m{Zxm;iLO?cSi&C{)3@32Dm~;gLg9wIU#F8B28R5m z-;WA5s?^`}=2tmz)o8ISRrlrtF17(?Q~x%D|9A=D761F?e?s`b6!=!_{$G`N0`K@3 zGV#Rjxp<~CM*CV?j4Uu2ih*f>`zJ$P3w}iOtdbd1OF_y$9A^B7emvWTN=;BjXf|EATb28`d$iqF@8p-3KNHCH;iq~jJxhvtfA)% z<$p}GeYbAte_wq77=(a@z#hF6Km4e}fOUUBC6l0sP~p;PRWVdhJEL|F9B4*t4{722 z9n?i6o2K6YUG0;4H}Ki+4{YkjWA*as@qihMHE)dKnW1-JUweXuSj?X>ETr~{BzcoM z5j3UYYUs~wi<^$kO-aCc2+5&r3%8@9>C?W&oi2Rhn7x7=-;89xf#daVSJj(IV)CcF z?*^vFs}X*TyP(p)*9M4fB&UN{by|+t^`(JUzixL@@6}~jTc~GTc>ZbuXgAEb#CM4P z(62y@6TFwM{Xz9^u%GOJDJs2m3H8kR(H^6<*`V85L>F$Tpa5SuIu|+Rf7Q@MPn@8{ zW-9P3LX?ZkdTE-|$j?4KxsW8tCr(Orw15OT|EhO*Y3STXDOIlI2^~{ENw&-IZT}rdS0RP{lv!kcR!#eOFwclH91^b9!>DrZ3JT0 z_kO96O-YcCB=jcUtO}fpSj141iDF6G85KMBpaw~@O^xdX~0AquVi`K4O zG}tmOv~S63XMe8hVMe8Ckf zt!JoE!Rmf|U`C6YZoQUbSCZ@0eNwu+Y|`#A1mpAz-{*o1k&K1dG6t(dQ+njbLLl*1 z>Yb5OK3g$07H|usNydM_1qV|}KJt)>QQ%3+bd^|2yBRgYNz;~}{3x4c9SA;rC>U`Ww3qm-;e z%CaW201?LDRJ#BgBH~J{W>m(g3cb5x!>eZuzcLw(7h%0>MyA%!XXB3`n}?7kkM-=3 zN+9$|JGJRh^XFaM+YlVkSUtR!*R=J5+DKM=5&6B5vSxwN0-^X0bE=Ey1S9AOpYV{* zGW4Iu(9=)dIv&$JsJu|rmBCcT4U>G5An|EIk#{Yx_c-Y-in%WQPC z($X3;b8U4=1$DH=eM@me&BhJGEpZLe>649_S+2Qanp+6C?}$yB8Je01?vzR@sN{ku z2z+T~YJUH~@7egsNAH{0xz9P*b*^*X=ca^EDvnt(4@wCd$A1HxmwCecZ#bVTA=ucD zSiRCW?2!odX9TB-$UpXM7_Rhoh}00AXw&RjDL3f44|hppF%r%(rT9D(S-37*PTj;( z!2j=2B-VDL!Qn}DmZQ##wUa zU&5pP*of6aorU6qgV@8_!CI4sv^+z|X5x>GasGi3H~@nk&E41)^-~t&)6epB&{)k& zZF&<$aBd`H43`Y|;dWd~MY1ePk!Dqt4%F6qQs~0E3OD(p5mp)1G_F9qa#F|a?2q^4 zAl43~H|RO%MNT^mH@RSomz}+l4HJI;dp06Bmg2%_ZX03U;h)x%8YW;PeDDPGBLF&j z^=Od-DT*KEYeRY^;HQ5XP`$MCTp5TEx66~lF|ZhWmYF?O!Pa@Xn;jQ0ATj?b4o7UM zpr!?EU6(>tW39(~QoDQ@^4d#-q6>mO7a571cZf5r?wAlK!M>EezLE0x|F3G+GzDt{^ya?&(gl zxh;j=)o$4Ziz;N4!vMQuYrEWvSGBr%bWM6A_k_JCoCLu~Mcj5<6!_v`PNxB8S2!su zY2RUINWyh>7(;WkMe*F$tf}G1F1Yl2TXuA|7vqxhSDZZq{^cgCegt?{Z5lD23A%%$ zm?H>*BjzWPI}GfU@va#*N{bGzr?UjZ7k^jKszO>yoB5_FluF=w+&N~u;_95K)hS+q zDY#efR82%n7N7SkEw^#I1VJ4%AD4Q~Ww!61)f3Xb~Q zK~B1WZuk-*`iXi)(Ja1?i;=ENrS#-5F= zrVDUw-?qqwGt%GFXQ{9za=J<4CJU!hVVwB~i6B)y#B;vKWJ4(wI$ zE8k%Tr5aKi-ag{k)CzHs;N+IJ>#9YOREz&XP z+kLqeSF;HS6dWsO#G##vfm^mSpu}=qB#D`u0(388 zVbU6bIJ?-ucwUhy98mHDRR(K1TYAYfRST z=ZGe!!48w_6xVPnJiiGVggF}= z9zWe33wuCi->$zkB6Gorzo-$H(mujmKFGT9L34A~?g@m#Go0G+pj4`rfRRy0nSya9 zTz1d|Y2!zGynm0keDOx|$rWj}p=+8jWvGKn_| zOyJ*fe!bGmP3*EQ*U(vNB}$2fb3>XP9Qb*XeBdqpM%SG`x2wmm46M;B+nK9fYW6+! z`LSLN8iw;~U~*<11AL`2ne0q6jznWZ$VGT}S}*%w9;TQO0|`Z;G)me9R~U>_#_@jy zfQ|8=oKT!cHa3qpvo$^FvGph-ycs+vN8N&~^{?k#MADiKOX5;I=(nOw@W00VcKd$q zma})(MXcHa)2n}|af!_w@Y`LZ`A_`BcSZ^65WK+(@1PlseB%07Q#uMU%Z%x;I9B92 z$OmqRmcV_pSS#&ykMeZhfgR@O?I1B+^)s_o9MScK(f`3nmWc@H9Xn4A9gCcvUEDJP zA*cz3h|>a)1M%Ke_e@sFB5@o}%MV(-N*c~fMm z6)Meb%T>kJ`(SVwZ(08?iyL-R^*FPpJCJ*#Ih<0ETielkedn?1frsz67gQ#+T+xi( z?5p;x*Co*gL58&FpdTrHQ%DO|GmFD- zbr~I^3#nGOo9GkuNPf5aVUhshJD&S z$f@ET_q4eBt25WGAk*7Z>AI2N03J%~3cZrVY;XW)l`D;3d+)jjvxvB0ZxW?awzDuz_uPfR%H8Y{YmrE7%nRW@}lkEu%MYlS>U5JzS-$8j!Cqq#6ul_zH6#-ga3xu{8C_i95#{DO#nr47WH-usr~ZxlG;a`snbSY7la|M8wwId ziy$kx!h#C5jB{r0fEViJohGv3badWa73wiK8;F?FbI&p^j^-9^a!J*k7_>5;zax3)$exV@;Dr|P&6-?Tjbo+DFJQ)i&Gf534;jWr-fv7*ckR<$ zsHPvtdBxnt{bE;{o?QYRrP9@8?A=QQuyFoCyvmA0k;{W!3Dd$rq%8flkss4zeN&nQ zz{65Q;SKh1iQ3xdLIQp-dfA`tJ3MjSvEk?+z_Y!aEq<((Uyx%&y}5d@RKoZXk4*m> zK_IoK27QE>eLLDHK?ZR{bkxe~7bCCzdm)Dnh{iFi(~7GKNq9?l?HB4e7z~ty;g;1X7j6fY zXKPj9I|{!(x=k`%_MX@FXZh<-LdUPU1Un>Ll`A3>H(M`azX|cBdu0}BAIzag3zUq! zED~bAlAw|U*2LXhTY|>N>Qp6pZK4Q-oVwQ)jGhXL;rxM^q+TPWuEz|iZ*+#rO=u-=W^^sQpRo1x%+p@UISO$ZQCn#9y`TSV zAqKyV6lnQ$Yb!^nGOA;OeZp?&pi3 zfwhO0%^yxDlg%DDQPZ^c0eaRyV_9af$8fc6rLMcn3U~s)&o&R}1`Iz4-xNb1`aowk%36J$3 zARZC>tyL|DW$1mNB3>dTq{GTqUw}?*DS=uy;A*vZ-^Mvxo8RNYibcAZrk~72tz1f7 zDmh<}6!o^QiT&>C2adN){pt`0T-?~S(?XZE7)ISR?!kI4=u*bRMXR{4@gPA{>LTt; z&4jtyg28v(GZPNVkKg?K~jGqW~SeDC19F=v~3G`1zXCq zQ2qjTg2u;rcQ#FE58vYz%oR}0DcN!jbcWoLS0t23dKR0UE+&3d=8O+vH~UD5?ZAkx z@`dp@FrIWt_K?NDWx0iBNZSUs1B0gTc^|qC2-?+wx@?4xcmsv^J)T%AO&QN)^fh%v-O{42`r`MKG6{3c5;&Twev zQ&?TT=MDG~v%b2jkGr_S3DbAn`q;cGRxEjA%VnZ^jGej|CEDh{Hu5;3pO(kurt1eW zUX{~t$9o`pfW#1F1)OGu>Nv$j{$r48h>&64A+iI>?}V3SEpKZ6al7iCjaF>SN_N3- z6OY^OSiPR|d%NsBJUaj-cG!FvZA@_rhM|md_$TcoqHebSv>-TI1MR0mY?NcMd~>Pt z&eAG^vdH;bf*uF`SN~O57;^G%kD%8QQ{=9|`hy=si@y77fLaLlCEl_`mG=HK$gdCV zFht3$;Iy@AiYk3ZOET!^S4Gq4q!VA<@?K%yk{tQhvGBXQd0^#$Lsm<9%^{-8T&J*h z;A+F6Fy^zFlFGTONj=(COWnO-<%d8@^`Xk|1;JjCv$mkGz^vzAR0mGe`}C^wGJ_m3 zMfj%AjrTrQ$=#Y~OF%~7f+C4;?Q->=o$nPmXsuRW(a8QxJB8L5^y@7Lsd?oy%kvQg zWM)2D(B5IU{_X*tRIE{~0poqQcV5n6({+C^&dx{siGp(dXg<{|EFZ=yD50w!9Hfh_ z=}z1l_c>(Eo6`S-n_f~zu$g#*CUJt+BCaUDlph_5(OY-0@A)Oe&{DCf7Rju`=l%3z zK;RM$K5#{X@_@fL><9h|OE=#e2ZLI!izaG#FfLusb39svuU_2@tg)$oxBc}At8P}d zElzQp{%GkbL43HGq^vrvt!PBpy?#U|U_zivB*UXJ>f{%qhplLv+Jc~vvF`*d9B3K4 zoZD%CVDb{K&1c3>Z;ARaogVDh$6{9T2fGYEJoiJ5U~wZ4fq7Str~9LRlL4v^QL9oKnB>qq z{puB>!y`Ik|HjP;vB`5S*Fe`=b z-iS#)wwcL9d1waLcf`0iM!I>f8pUA(Na!Z`wnxBQ-iKMS7_IFJ(?Dc)zyIxTb~|{j zh@f`!{$fU=pm9+x)D$?n)~ae4Sb4usXCU{tWahbsZa-kIRS`y3&G4rRV+RoR@oBvm zsNdY?wo&&Ys2V_I&vhM}Qk$h0Gr7}ot`f}pisD8$I*Q+5NGZKKOBLK4HlhfLEWndd zsoy&1w8b8@IlL+QNGX-fuFn-2zluL{_a?3xwgB0$4hii| zJU6%||0f+rcCt&T} zc^Zz&I@7rew~d^Yh5g`0?w9_!AjJn|#eR8Cux@jnf~-CY05uBMo$pQj#Va0|q4DCx z-hCNHgxA4S__6MjxV3uK`3Cd$KcnfNLty-twP7K!H3y4*5c}E&G&ENbs~lKx_&Iq$ znozbfD^(}B5M=+@u`shVPM4JS#-l=H0U0#e^(GxrAt7~V5+)GioMi+x3b(eK8-!91RR5X{q*x&M6+J+O{8nr09d8@h zv=;N;*`fJQjANAy4uFYGg;-lEA*Py(b6r+*O%(=2{3oTq$%}spmg~~GCr6ridWFh; zgWZ1GK@>*cV519&%SeQy7-tKww^*w}afTW(yu04@eh=l!I}YsJz8k{l5L;{>a-9YF z?jzY`oIOoaxKRN1xRFC9SD_oK5ah>M!%}Df(j)U*dj0!J!w1|iqe$>k4T(ueE;Xgx ze@3Iu8a+`9jYJlM!RXq@dp5E!PkU&v9sutujEq>{=8t>6`vG2CmNDKw~j8D-XKjnLm!KjT(ZhVqn7bG1WFr%GhR(^#n zO`lMrJ=!*4Aq_3L;OtZ4gQ#G}jmLEWKNsKYw1qYLUewh0bSfa3g;~=d!i=<6T44># zw~}(x+FZso6byiNEYg#_$Z_f`0NC2ksx|3-t@vQ7C8K;w2G#5VIFBLNdqy)eyV^AZ zt9b)Seo7Fe?rA}D3|xRAzmbG#HIr|N#<2#O?nCvY8ciU~Lun%dPb)pTQ0f7LGudxoSru|^5D0I#bPw2cf^o@+Fb zYpJ|-5q(c97(Ze8{7{^;CkWIuTz}R?t_Y-{ki9S)S;;H=ZqVIA4*Q7G%Rte$@Z-my zIP@4O90uhDp%#kHP_-gS6$|6CeAh9v>+Z#E|Jo@TjbMXnTEd@`Z+7}TgLf|F*!RWv???*r87@a z5sY2hbG7cq6hPMcy=L;$O_bS$eUotg*=+NVsi)6C2UIoqt6TMP&&Lj9i&8h6jxg&H z1~E5Z{HrYV?wu~|22po$JJN?PyTrJNEJ!%N;FfhWu20Di7P|w@4AcFGzFZyH?rwIk z6lS;Po5&Y2avI}QhGN`Edko!{XX(w~gx7?{y|ihCZyem@=ZbPwO6VWr^kyrhMF(O* zcV4wT5P;*3e(Laj(y1lP77?do7vHA(KgD;HeI4xLNPz;LBJ3PUcT#0_k&P867AmIZ z&kVeg>M=Ao4%f+zX>67x;eUD^tvZ{tLItsB% z7{RroIpaOOC3=->S@P_URqfKMlYe0czL}H8l zhXu~!rI^5&>whDaYECpE$&}t~OSLA#KWc3q_1=zqbFHBd+|L_Jgkp(3N&+B#Vm6FF zrB*+kjR6Fd_`37*t32_FqRKqzTlaMjobO2@V`o`P>yp>LQtQhNsv2Qr%GSe1$k*0( z4w^HT`U730#E3;zD+hvLS4&at%B3mf=heaM&g~+mU}iM5u=OIM=Isgg)HSFAbG9R8 z!Vt=C)zgREPA0oqPE;Qvp<;&vt2_KDIUdThJl)XVuEF=2AB$u-X4I;O+y+&w`Ha)D zJe8Rlh;A%w|NEJp=KG0&+5t=ANZwEa$<`y#i`~_ARWjMOF!Netb*zm<0k(1!rqyzl zV`DKr6}#}}vg7fgiUI0Yf7f9)7`oMO>giBWKK1Z}xt!!LM4!R$Mfi??o$TTzT~&=Ot0_O- zdYK)xc7iDNE8rNO(3l!Fg)QH-aj*jW1TjB#dFGTEi<2w;bS43-ye|KVgP$AX{N&S} zGj>m(dx-`k_H;f>UoTF|q6V2w(@szBanp7W`hhJ6ma;yO>qk>hvw=~3Q<{OQ9c8(_ zqSRV7|LMY?D|dSx?k9AZTa_TL6|Y1xin$c?!tv}x587);ux0qr{QK4Au04__njo9m z!l%!B7}3W@k~$4-CNB!+*ksU?SHv+n{rUa;UAqqIn3)>iJOy65)N^`3I!0(~gy_KW zJF<*9?x+03`Wp*Bn$h_SFV)93Ue+YO(@Qw0FzZB`uC5(_T5ZVZicT-^xvt9Uhc1q! zfLrkoX!-1%Ng~(`y@(kEiRbgQR&gpMBrKDgR@BJaozzOx3#fFH0wQ&_?L@yO+hej5 zo$%!a-e4||)g>zFcSff4`18bR6+7kos+i{stwibhm}@57LJ+Zod%x?K?A!|u9D=yi zaQ;mLEjs+{>Z&QSbQ~U4Z2eKND83se8C;J=+?e#XcX)dMxfapPl!2roBKrJc?AMQ^jZl^ zS~j0bTcsA*DF*;sFF_(K;bnh0hF}m+WT8LFQNSPLg=u2+=_G)p79fsg$_4Lu6d!u0 z2GOGzdumu5`B_L!!&V}rin9KwRm=?w`yCzEGhjg+Ces^5evB4;7kdBcXn%LT??moL z%>DPzccJD#i~Z*$-$DEzitwLH{O1z?xx{}_@Lv@C7X|-C!T;AN@RCj7OTb^7UPC&$ SKiwtxGrMYSiuu*+_x}UBP>2Ko literal 48319 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 a{RWp%i6*@pp11u0_{m5pidTyo2mBw^N8dC6 diff --git a/start.sh b/start.sh index 26b46c5c..25ebada1 100644 --- a/start.sh +++ b/start.sh @@ -20,16 +20,15 @@ TAG=$(curl -sX POST \ if [ -z ${MODEL} ] ; then - echo -e "\033[91mWARNING: MODEL variable not set.\n Set the model of the gateway you are using.\033[0m" + echo -e "\033[91mWARNING: MODEL variable not set.\n Set the model of the gateway you are using (SX1301 or SX1302).\033[0m" balena-idle else echo "Using MODEL: $MODEL" - if [ "$MODEL" = "RAK2245" ] || [ "$MODEL" = "iC880a" ];then - ./start_rak2245.sh - + if [ "$MODEL" = "SX1301" ] || [ "$MODEL" = "RAK2245" ] || [ "$MODEL" = "iC880a" ];then + ./start_sx1301.sh fi - if [ "$MODEL" = "RAK2287" ];then - ./start_rak2287.sh + if [ "$MODEL" = "SX1302" ] || [ "$MODEL" = "RAK2287" ];then + ./start_sx1302.sh fi fi diff --git a/start_rak2245.sh b/start_sx1301.sh similarity index 100% rename from start_rak2245.sh rename to start_sx1301.sh diff --git a/start_rak2287.sh b/start_sx1302.sh similarity index 100% rename from start_rak2287.sh rename to start_sx1302.sh From 84e977680a5af986155715d983d9519a93971c8b Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 12 Mar 2021 12:53:22 +0100 Subject: [PATCH 54/88] Update balena.yml Deleting TC_URI to let the TC_URI gets autogenerated with the TTN_STACK_VERSION and TTN_REGION --- balena.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/balena.yml b/balena.yml index 4abad7de..235e1409 100644 --- a/balena.yml +++ b/balena.yml @@ -15,7 +15,6 @@ data: - GW_GPS: false - GW_RESET_PIN: 11 - GW_RESET_GPIO: 17 - - TC_URI: wss://lns.eu.thethings.network:443 - MODEL: SX1301 - TTN_STACK_VERSION: 2 - TTN_REGION: eu From 3a527357148d735cd4e7bb51d361736aacb6c526 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 12 Mar 2021 12:54:29 +0100 Subject: [PATCH 55/88] Update balena.yml --- balena.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/balena.yml b/balena.yml index 235e1409..f5c84a95 100644 --- a/balena.yml +++ b/balena.yml @@ -1,5 +1,5 @@ -name: "TTN basicstation Gateway V3 and V2" -description: "Deploys a TTN or The Things Stack LoRaWAN gateway with Basics Station Packet Forward protocol. It runs on a Raspberry Pi or Fin with a RAK2245 and 2287 concentrators." +name: "TTN V2 V3 basicstation Gateway" +description: "Deploys a TTN or The Things Stack LoRaWAN gateway with Basics Station Packet Forward protocol on SX1301 or SX1302 LoRa concentrators." type: "sw.application" assets: repository: From 7da9e3e2b22028fa3d7f6eab1c891fa0110ce54a Mon Sep 17 00:00:00 2001 From: Abhijeet Bhatikar Date: Tue, 30 Mar 2021 23:26:23 +0100 Subject: [PATCH 56/88] Add SPI_SPEED device env. variable remove hardcoded spi device in the startup script --- deps/lgw/v5.0.1-kerlink.patch | 3 ++- deps/lgw/v5.0.1-linux.patch | 2 +- deps/lgw/v5.0.1-rpi.patch | 2 +- start_common.sh | 1 + start_sx1301.sh | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/deps/lgw/v5.0.1-kerlink.patch b/deps/lgw/v5.0.1-kerlink.patch index 8a2281b6..2e9a122f 100644 --- a/deps/lgw/v5.0.1-kerlink.patch +++ b/deps/lgw/v5.0.1-kerlink.patch @@ -125,7 +125,8 @@ index c01ed1c..0e2b64c 100644 @@ -54,7 +54,7 @@ Maintainer: Sylvain Miermont #define READ_ACCESS 0x00 #define WRITE_ACCESS 0x80 - #define SPI_SPEED 8000000 +-#define SPI_SPEED 8000000 ++#define SPI_SPEED (getenv("SPI_SPEED")==NULL ? 8000000 : getenv("SPI_SPEED")) -#define SPI_DEV_PATH "/dev/spidev0.0" +#define SPI_DEV_PATH (getenv("LORAGW_SPI")==NULL ? "/dev/spidev0.0" : getenv("LORAGW_SPI")) //#define SPI_DEV_PATH "/dev/spidev32766.0" diff --git a/deps/lgw/v5.0.1-linux.patch b/deps/lgw/v5.0.1-linux.patch index 7d80091d..4a936202 100644 --- a/deps/lgw/v5.0.1-linux.patch +++ b/deps/lgw/v5.0.1-linux.patch @@ -126,7 +126,7 @@ index c01ed1c..0e2b64c 100644 #define READ_ACCESS 0x00 #define WRITE_ACCESS 0x80 -#define SPI_SPEED 8000000 -+#define SPI_SPEED 2000000 ++#define SPI_SPEED (getenv("SPI_SPEED")==NULL ? 2000000 : getenv("SPI_SPEED")) -#define SPI_DEV_PATH "/dev/spidev0.0" +#define SPI_DEV_PATH (getenv("LORAGW_SPI")==NULL ? "/dev/spidev0.0" : getenv("LORAGW_SPI")) //#define SPI_DEV_PATH "/dev/spidev32766.0" diff --git a/deps/lgw/v5.0.1-rpi.patch b/deps/lgw/v5.0.1-rpi.patch index 7d80091d..4a936202 100644 --- a/deps/lgw/v5.0.1-rpi.patch +++ b/deps/lgw/v5.0.1-rpi.patch @@ -126,7 +126,7 @@ index c01ed1c..0e2b64c 100644 #define READ_ACCESS 0x00 #define WRITE_ACCESS 0x80 -#define SPI_SPEED 8000000 -+#define SPI_SPEED 2000000 ++#define SPI_SPEED (getenv("SPI_SPEED")==NULL ? 2000000 : getenv("SPI_SPEED")) -#define SPI_DEV_PATH "/dev/spidev0.0" +#define SPI_DEV_PATH (getenv("LORAGW_SPI")==NULL ? "/dev/spidev0.0" : getenv("LORAGW_SPI")) //#define SPI_DEV_PATH "/dev/spidev32766.0" diff --git a/start_common.sh b/start_common.sh index 89ed8672..c9d16100 100644 --- a/start_common.sh +++ b/start_common.sh @@ -27,3 +27,4 @@ declare -a pinToGPIO pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) GW_RESET_PIN=${GW_RESET_PIN:-11} GW_RESET_GPIO=${GW_RESET_GPIO:-${pinToGPIO[$GW_RESET_PIN]}} +LORAGW_SPI=${LORAGW_SPI:-"/dev/spidev0.0"} diff --git a/start_sx1301.sh b/start_sx1301.sh index e8a47617..f9e63ecd 100755 --- a/start_sx1301.sh +++ b/start_sx1301.sh @@ -22,4 +22,4 @@ echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value echo $GW_RESET_GPIO > /sys/class/gpio/unexport -RADIODEV=/dev/spidev0.0 ../../build-rpi-std/bin/station +RADIODEV=$LORAGW_SPI ../../build-rpi-std/bin/station From 148a5432f6c7fed8b55613751723ceba976ae32b Mon Sep 17 00:00:00 2001 From: Abhijeet Bhatikar Date: Tue, 30 Mar 2021 23:28:07 +0100 Subject: [PATCH 57/88] Add a delay for the reset operation for sx1301 --- start_sx1301.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/start_sx1301.sh b/start_sx1301.sh index f9e63ecd..b170f919 100755 --- a/start_sx1301.sh +++ b/start_sx1301.sh @@ -18,8 +18,11 @@ echo "Resetting gateway concentrator on GPIO $GW_RESET_GPIO" echo $GW_RESET_GPIO > /sys/class/gpio/export echo out > /sys/class/gpio/gpio$GW_RESET_GPIO/direction echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +sleep 1 echo 1 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +sleep 1 echo 0 > /sys/class/gpio/gpio$GW_RESET_GPIO/value +sleep 1 echo $GW_RESET_GPIO > /sys/class/gpio/unexport RADIODEV=$LORAGW_SPI ../../build-rpi-std/bin/station From a21b9f5aa3e08e1f327649a29f4fe17c33d86071 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 13 May 2021 23:02:29 +0200 Subject: [PATCH 58/88] Update balena.yml Update balena.yml for openFleets --- balena.yml | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/balena.yml b/balena.yml index f5c84a95..f240d2ab 100644 --- a/balena.yml +++ b/balena.yml @@ -1,15 +1,18 @@ -name: "TTN V2 V3 basicstation Gateway" -description: "Deploys a TTN or The Things Stack LoRaWAN gateway with Basics Station Packet Forward protocol on SX1301 or SX1302 LoRa concentrators." -type: "sw.application" +name: 'The Things Stack Gateway' +type: sw.application +description: >- + Deploys the The Things Stack LoRaWAN gateway with Basics Station + Packet Forward protocol on SX1301 or SX1302 LoRa concentrators. assets: repository: - type: "blob.asset" + type: blob.asset data: - url: "https://github.com/balenalabs/basicstation" + url: 'https://github.com/balenalabs/basicstation' logo: - type: "blob.asset" + type: blob.asset data: - url: "https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png" + url: >- + https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png data: applicationEnvironmentVariables: - GW_GPS: false @@ -21,9 +24,8 @@ data: - GW_ID: 0 - GW_KEY: 0 - TC_KEY: 0 - defaultDeviceType: "raspberry-pi3" + defaultDeviceType: raspberry-pi3 supportedDeviceTypes: - - "raspberrypi3" - - "raspberrypi3-64" - - "raspberrypi4-64" - - "fincm3" + - raspberrypi3-64 + - raspberrypi4-64 + - fincm3 From 28c8f077e8482d22812ad31e65ffbe35059e8b32 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 13 May 2021 23:07:24 +0200 Subject: [PATCH 59/88] Update balena.yml --- balena.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index f240d2ab..75602397 100644 --- a/balena.yml +++ b/balena.yml @@ -1,8 +1,13 @@ -name: 'The Things Stack Gateway' +name: The Things Stack Gateway type: sw.application description: >- Deploys the The Things Stack LoRaWAN gateway with Basics Station Packet Forward protocol on SX1301 or SX1302 LoRa concentrators. +fleetcta: Build a LoRaWAN gateway +post-provisioning: >- + ## Usage instructions + Once your device joins the fleet you'll need to get the EUI of the device and create a gateway on The Things Network (V2) or The Things Stack (V3). + For detailed instructions on how to use configure your LoRaWAN gteway check out the [readme here](https://github.com/balenalabs/basicstation). assets: repository: type: blob.asset From e382253d3eb16ea7bd3fb4b1e33863da350b0b5a Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 13 May 2021 23:52:34 +0200 Subject: [PATCH 60/88] Update balena.yml --- balena.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/balena.yml b/balena.yml index 75602397..9082fade 100644 --- a/balena.yml +++ b/balena.yml @@ -6,7 +6,9 @@ description: >- fleetcta: Build a LoRaWAN gateway post-provisioning: >- ## Usage instructions + Once your device joins the fleet you'll need to get the EUI of the device and create a gateway on The Things Network (V2) or The Things Stack (V3). + For detailed instructions on how to use configure your LoRaWAN gteway check out the [readme here](https://github.com/balenalabs/basicstation). assets: repository: From 960545f1db0cf69e66d1ceca2317cc96896dc8b5 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 14 May 2021 00:39:12 +0200 Subject: [PATCH 61/88] Update balena.yml --- balena.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/balena.yml b/balena.yml index 9082fade..1708d787 100644 --- a/balena.yml +++ b/balena.yml @@ -33,6 +33,7 @@ data: - TC_KEY: 0 defaultDeviceType: raspberry-pi3 supportedDeviceTypes: + - raspberry-pi3 - raspberrypi3-64 - raspberrypi4-64 - fincm3 From e5bd11f6e5211e58150074cd2039de5d9c6fd356 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 14 May 2021 01:04:35 +0200 Subject: [PATCH 62/88] Update balena.yml --- balena.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/balena.yml b/balena.yml index 1708d787..b387930f 100644 --- a/balena.yml +++ b/balena.yml @@ -31,9 +31,9 @@ data: - GW_ID: 0 - GW_KEY: 0 - TC_KEY: 0 - defaultDeviceType: raspberry-pi3 + defaultDeviceType: raspberrypi3 supportedDeviceTypes: - - raspberry-pi3 + - raspberrypi3 - raspberrypi3-64 - raspberrypi4-64 - fincm3 From 2a9841f700f8a77a08709e182b96f085fcf77fbc Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 20 May 2021 20:16:04 +0200 Subject: [PATCH 63/88] Update balena.yml Adding joinable false --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index b387930f..a897445d 100644 --- a/balena.yml +++ b/balena.yml @@ -3,7 +3,7 @@ type: sw.application description: >- Deploys the The Things Stack LoRaWAN gateway with Basics Station Packet Forward protocol on SX1301 or SX1302 LoRa concentrators. -fleetcta: Build a LoRaWAN gateway +joinable: false post-provisioning: >- ## Usage instructions From a51605cedb24d2701d6b347a2bd8c9309832c48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Tue, 25 May 2021 10:43:57 +0200 Subject: [PATCH 64/88] Remove trailing unmatched bracket --- start_common.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start_common.sh b/start_common.sh index c9d16100..bee3412c 100644 --- a/start_common.sh +++ b/start_common.sh @@ -3,11 +3,11 @@ TTN_STACK_VERSION=${TTN_STACK_VERSION:-2} if [ $TTN_STACK_VERSION -eq 2 ]; then TTN_REGION=${TTN_REGION:-"eu"} TC_URI=${TC_URI:-"wss://lns.${TTN_REGION}.thethings.network:443"} - TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/trustid-x3-root.pem.txt"))} + TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/trustid-x3-root.pem.txt")} elif [ $TTN_STACK_VERSION -eq 3 ]; then TTN_REGION=${TTN_REGION:-"eu1"} TC_URI=${TC_URI:-"wss://${TTN_REGION}.cloud.thethings.network:8887"} - TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}"))} + TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}")} else echo -e "\033[91mERROR: Wrong TTN_STACK_VERSION value, should be either 2 o 3.\033[0m" balena-idle From 098affd0d5fca2942bdf508be3c4a9fd3831fbe9 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 28 May 2021 16:32:53 +0200 Subject: [PATCH 65/88] Update balena.yml Setting TTN STACK VERSION on v3 as default and not v2 as before due the TTN to TTS migration --- balena.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/balena.yml b/balena.yml index a897445d..ef426fe8 100644 --- a/balena.yml +++ b/balena.yml @@ -26,8 +26,8 @@ data: - GW_RESET_PIN: 11 - GW_RESET_GPIO: 17 - MODEL: SX1301 - - TTN_STACK_VERSION: 2 - - TTN_REGION: eu + - TTN_STACK_VERSION: 3 + - TTN_REGION: eu1 - GW_ID: 0 - GW_KEY: 0 - TC_KEY: 0 From bf4c30b41e5c35e72f1515d12d8420a967fd4cc8 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 28 May 2021 16:35:54 +0200 Subject: [PATCH 66/88] Update README.md Setting V3 as default The Things platform as everything is moving to The Things Stack --- README.md | 51 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index f1d01df1..a8e6aa26 100644 --- a/README.md +++ b/README.md @@ -88,18 +88,7 @@ If that does not work, go to the terminal box and click "Select a target", then Copy the result and you are ready to register your gateway with this EUI. -### Configure your The Things Network gateway - -1. Sign up at [The Things Network console](https://console.thethingsnetwork.org/). -2. Click Gateways button. -3. Click the "Register gateway" link. -4. Check “I’m using the legacy packet forwarder” checkbox. -5. Paste the EUI from the balenaCloud tag or the Ethernet mac address of the board (calculated above) -6. Complete the form and click Register gateway. -7. Copy the Key generated on the gateway page. - - -### Configure your The Things Stack gateway (The Things Conference 2021) +### Configure your The Things Stack gateway (V3) 1. Sign up at [The Things Stack console](https://ttc.eu1.cloud.thethings.industries/console/). 2. Click "Go to Gateways" icon. @@ -112,6 +101,15 @@ Copy the result and you are ready to register your gateway with this EUI. 9. Select "Grant individual rights" and then "Link as Gateway to a Gateway Server for traffic exchange ..." and then click "Create API key". 10. Copy the API key generated. and bring it to balenaCloud as ```TC_KEY```. +### Configure your The Things Network gateway (V2) + +1. Sign up at [The Things Network console](https://console.thethingsnetwork.org/). +2. Click Gateways button. +3. Click the "Register gateway" link. +4. Check “I’m using the legacy packet forwarder” checkbox. +5. Paste the EUI from the balenaCloud tag or the Ethernet mac address of the board (calculated above) +6. Complete the form and click Register gateway. +7. Copy the Key generated on the gateway page. ### Balena LoRa Basics Station Service Variables @@ -131,37 +129,36 @@ Variable Name | Value | Description | Default **`GW_GPS`** | `STRING` | Enables GPS | true or false **`GW_RESET_PIN`** | `INT` | Pin number that resets (Raspberry Pi header number) | 11 **`GW_RESET_GPIO`** | `INT` | GPIO number that resets (Broadcom pin number, if not defined, it's calculated based on the GW_RESET_PIN) | 17 -**`TTN_STACK_VERSION`** | `INT` | If using TTN, version of the stack. It can be either 2 (TTNv2) or 3 (TTS) | 2 -**`TTN_REGION`** | `STRING` | Region of the TTN server to use | ```eu``` when using TTNv2, ```eu1``` for TTS -**`TC_URI`** | `STRING` | basics station TC URI to get connected. | ```wss://lns.eu.thethings.network:443``` +**`TTN_STACK_VERSION`** | `INT` | If using TTN, version of the stack. It can be either 2 (TTNv2) or 3 (TTS) | 3 +**`TTN_REGION`** | `STRING` | Region of the TTN server to use | ```eu1``` (when using TTN v2 use ```eu```) +**`TC_URI`** | `STRING` | basics station TC URI to get connected. | **`TC_TRUST`** | `STRING` | Certificate for the server | Automatically retrieved from LetsEncryt based on the `TTN_STACK_VERSION` value **`MODEL`** | `STRING` | ```SX1301``` or ```SX1302``` | ```SX1301``` -#### The Things Network (TTNv2) Specific Variables +#### The Things Stack (TTS) Specific Variables (V3) -Remember to copy the The Things Network gateway KEY and ID to configure your board variables on balenaCloud. - -The `GW_ID`and `GW_KEY` variables have been generated automatically when the Application has been created with the Deploy with Balena button. Replace the values with the KEY and ID from the TTN console. +Remember to generate an API Key and copy it. It will be the ```TC_KEY```. -The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://lns.eu.thethings.network:443``` if you set `TTN_STACK_VERSION` to 2. If your region is not EU you can set it using ```TTN_REGION```, Possible values are ```eu```, ```us```, ```in``` and ```au```. +The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://eu1.cloud.thethings.network:8887``` if you set `TTN_STACK_VERSION` to 3.If your region is not EU you can set it using ```TTN_REGION```. At the moment there is only one server avalable is ```eu1```. Variable Name | Value | Description | Default ------------ | ------------- | ------------- | ------------- -**`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) -**`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) +**`TC_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) -#### The Things Stack (TTS) Specific Variables +#### The Things Network (TTNv2) Specific Variables (V2) -Remember to generate an API Key and copy it. It will be the ```TC_KEY```. +Remember to copy the The Things Network gateway KEY and ID to configure your board variables on balenaCloud. -The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://eu1.cloud.thethings.network:8887``` if you set `TTN_STACK_VERSION` to 3.If your region is not EU you can set it using ```TTN_REGION```. At the moment there is only one server avalable is ```eu1```. +The `GW_ID`and `GW_KEY` variables have been generated automatically when the Application has been created with the Deploy with Balena button. Replace the values with the KEY and ID from the TTN console. + +The `TC_URI` and `TC_TRUST` values are automatically populated to use ```wss://lns.eu.thethings.network:443``` if you set `TTN_STACK_VERSION` to 2. If your region is not EU you can set it using ```TTN_REGION```, Possible values are ```eu```, ```us```, ```in``` and ```au```. Variable Name | Value | Description | Default ------------ | ------------- | ------------- | ------------- -**`TC_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) - +**`GW_ID`** | `STRING` | TTN Gateway EUI | (EUI) +**`GW_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) At this moment your LoRaWAN gateway should be up and running. Check on the TTN or TTS console if it shows the connected status. From 96c9fb1bbb51d8fb4be518c77afe5f998973ee0d Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 1 Jun 2021 14:17:19 +0200 Subject: [PATCH 67/88] Update balena.yml --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index ef426fe8..318bdd9e 100644 --- a/balena.yml +++ b/balena.yml @@ -7,7 +7,7 @@ joinable: false post-provisioning: >- ## Usage instructions - Once your device joins the fleet you'll need to get the EUI of the device and create a gateway on The Things Network (V2) or The Things Stack (V3). + Fork this fleet and deploy the project on a balenaCloud application. Once the project released on a device, you'll need to get the EUI of the device and create a gateway on The Things Stack (V3). For detailed instructions on how to use configure your LoRaWAN gteway check out the [readme here](https://github.com/balenalabs/basicstation). assets: From 8ace76a155ab2317ade2af35b572cf731fffb88d Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 10 Jun 2021 15:57:42 +0200 Subject: [PATCH 68/88] Update README.md --- README.md | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a8e6aa26..1e5841ed 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ # LoRa Basics™ Station using balena.io with sx1301 and sx1302 LoRa concentrators -This project deploys a LoRaWAN gateway with Basics Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with a RAK2245, RAK2287 and IMST iC880a LoRa concentrators (sx1301 and sx1302). +This project deploys a LoRaWAN gateway with Basics™ Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with sx1301 and sx1302 LoRa concentrators (e.g. RAK833, RAK2245, RAK2287 and IMST iC880a among others). ## Introduction -Deploy a The Things Network (TTN), The Things Industries (TTI) or The Things Stack (TTS) LoRaWAN gateway running the Basics Station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. +Deploy a The Things Stack (TTS v3) LoRaWAN gateway running the Basics™ Station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. This project has been tested with The Things Network (TTN v2) and The Things Industries (TTI) as well. -The Basics Station protocol enables the LoRa gateways with a reliable and secure communication between the gateways and the cloud and it is becoming the standard Packet Forward protocol used by most of the LoRaWAN operators. +The Basics™ Station protocol enables the LoRa gateways with a reliable and secure communication between the gateways and the cloud and it is becoming the standard Packet Forward protocol used by most of the LoRaWAN operators. ## Getting started ### Hardware -* Raspberry Pi 4 or [balenaFin](https://www.balena.io/fin/) +* Raspberry Pi 3/4 or [balenaFin](https://www.balena.io/fin/) * SD card in case of the RPi 4 #### LoRa Concentrators @@ -22,6 +22,7 @@ The Basics Station protocol enables the LoRa gateways with a reliable and secure * SX1301 * [IMST iC880a](https://shop.imst.de/wireless-modules/lora-products/8/ic880a-spi-lorawan-concentrator-868-mhz) * [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) + * RAK833 * SX1302 * [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) with [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) @@ -29,7 +30,7 @@ The Basics Station protocol enables the LoRa gateways with a reliable and secure ### Software -* A TTN or The Things Stack V3 account ([sign up here](https://console.thethingsnetwork.org)) or [here](https://ttc.eu1.cloud.thethings.industries/console/) +* A The Things Stack V3 account [here](https://ttc.eu1.cloud.thethings.industries/console/) * A balenaCloud account ([sign up here](https://dashboard.balena-cloud.com/)) * [balenaEtcher](https://balena.io/etcher) @@ -61,7 +62,9 @@ If you are a balena CLI expert, feel free to use balena CLI. ### Define your MODEL -The model is defined depending on the version of the concentrator: ```SX1301``` or ```SX1302```. In case that your LoRa concentrator is a ```RAK2287``` it is using ```SX1302```. If the concentrator is the ```RAK2245``` or ```iC880a``` it uses the ```SX1301```. It's important to change the balenaCloud Device Variable with the correct ```MODEL```. The default ```MODEL``` on the balena Application is the ```SX1301```. +The model is defined depending on the version of the concentrator: ```SX1301``` or ```SX1302```. + +In case that your LoRa concentrator is a ```RAK2287``` it is using ```SX1302```. If the concentrator is the ```RAK2245``` or ```iC880a``` it uses the ```SX1301```. It's important to change the balenaCloud Device Variable with the correct ```MODEL```. The default ```MODEL``` on the balena Application is the ```SX1301```. 1. Go to balenaCloud dashboard and get into your LoRa gateway device site. 2. Click "Device Variables" button on the left menu and change the ```MODEL``` variable to ```SX1302``` if needed. @@ -70,16 +73,19 @@ That enables a fleet of LoRa gateways with both (e.g.) ```RAK2245``` and ```RAK2 ### Define your REGION and TTN STACK VERSION -From now it's important to facilitate the ```TTN_STACK_VERSION``` that you are going to use ```2``` (TTN v2) or ```3``` (The Things Stack or TTN V3). The default variable is defined (still) into ```2```(V2). +From now it's important to facilitate the ```TTN_STACK_VERSION``` that you are going to use: ```3``` (The Things Stack v3) or ```2``` (The Things Network or TTN V2). The default variable is set into ```3```(V3). + Before starting, also check the ```TTN_REGION```. It needs to be changed if your region is not Europe. In case you use version 3, the European version is ```eu1```. Check [here](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html) the LoRa frequencies by country. -With these variables ```TTN_REGION``` and ```TTN_STACK_VERSION``` the ```TC_URI``` will be generated automatically. In case that you want to point to another specific TC_URI, feel free to change this Device Variable on the balenaCloud. +With these variables ```TTN_REGION``` and ```TTN_STACK_VERSION``` the ```TC_URI``` will be generated automatically. In case that you want to point to another specific ```TC_URI```, feel free to add this Device Variable on the balenaCloud. ### Get the EUI of the LoRa Gateway -The LoRa gateways are manufactured with a unique 64 bits (8 bytes) identifier, called EUI, which can be used to register the gateway on The Things Network. To get the EUI from your board it’s important to know the Ethernet MAC address of it. The TTN EUI will be the Ethernet mac address (6 bytes), which is unique, expanded with 2 more bytes (FFFE). This is a standard way to increment the MAC address from 6 to 8 bytes. +The LoRa gateways are manufactured with a unique 64 bits (8 bytes) identifier, called EUI, which can be used to register the gateway on The Things Network and The Things Stack. To get the EUI from your board it’s important to know the Ethernet MAC address of it (this is not going to work if your device does not have Ethernet port). + +The ```EUI``` will be the Ethernet mac address (6 bytes), which is unique, expanded with 2 more bytes (FFFE). This is a standard way to increment the MAC address from 6 to 8 bytes. -To get the EUI, copy the TAG of the device which will be generated automatically when the device gets provisioned on balenaCloud. +To get the ```EUI```, copy the TAG of the device which will be generated automatically when the device gets provisioned on balenaCloud for first time. Be careful when you copy the tag, as other characters will be copied. If that does not work, go to the terminal box and click "Select a target", then “HostOS”. Once you are inside the shell, type: @@ -131,10 +137,9 @@ Variable Name | Value | Description | Default **`GW_RESET_GPIO`** | `INT` | GPIO number that resets (Broadcom pin number, if not defined, it's calculated based on the GW_RESET_PIN) | 17 **`TTN_STACK_VERSION`** | `INT` | If using TTN, version of the stack. It can be either 2 (TTNv2) or 3 (TTS) | 3 **`TTN_REGION`** | `STRING` | Region of the TTN server to use | ```eu1``` (when using TTN v2 use ```eu```) -**`TC_URI`** | `STRING` | basics station TC URI to get connected. | **`TC_TRUST`** | `STRING` | Certificate for the server | Automatically retrieved from LetsEncryt based on the `TTN_STACK_VERSION` value **`MODEL`** | `STRING` | ```SX1301``` or ```SX1302``` | ```SX1301``` - +**`TC_URI`** | `STRING` | basics station TC URI to get connected. | #### The Things Stack (TTS) Specific Variables (V3) @@ -168,6 +173,9 @@ At this moment your LoRaWAN gateway should be up and running. Check on the TTN o It's possible that on the TTN Console the gateway appears as Not connected if it's not receiving any LoRa message. Sometimes the websockets connection among the LoRa Gateway and the server can get broken. However a new LoRa package will re-open the websocket between the Gateway and TTN or TTI. This issue should be solved with the TTN v3. +Feel free to introduce issues on this repo and contribute with solutions. + + ## TTNv2 to TTS migration Initial state: one of more devices connected to TTNv2 stack (The Things Network). @@ -180,6 +188,7 @@ Proposed procedure: Now you can move them from TTS to TTNv2 back and forth (using the `TTN_STACK_VERSION` variable) as you wish as long as the gateways are defined on both platforms and the `TC_KEY` and `GW_KEY` do not change. + ## Attribution - This is an adaptation of the [Semtech Basics Station repository](https://github.com/lorabasics/basicstation). Documentation [here](https://doc.sm.tc/station). From 1c969b13fd402beafdc4404cb7d3b95d20ec3571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Tue, 15 Jun 2021 22:46:21 +0200 Subject: [PATCH 69/88] Added code to sanitize TC_TRUST variable --- start_common.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/start_common.sh b/start_common.sh index bee3412c..9b683cb0 100644 --- a/start_common.sh +++ b/start_common.sh @@ -22,6 +22,9 @@ fi echo "Server: $TC_URI" +# Sanitize TC_TRUST +TC_TRUST=$(echo $TC_TRUST | sed 's/-----BEGIN CERTIFICATE-----/-----BEGIN CERTIFICATE-----\n/' | sed 's/-----END CERTIFICATE-----/\n-----END CERTIFICATE-----/' | sed 's/\n\n/\n/g') + # declare map of hardware pins to GPIO on Raspberry Pi declare -a pinToGPIO pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) From 182d009541116a640e2fd55c7c9c456f9a66cbf4 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 24 Jun 2021 13:20:11 +0200 Subject: [PATCH 70/88] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1e5841ed..75c5ea6c 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,12 @@ The Basics™ Station protocol enables the LoRa gateways with a reliable and sec #### LoRa Concentrators * SX1301 - * [IMST iC880a](https://shop.imst.de/wireless-modules/lora-products/8/ic880a-spi-lorawan-concentrator-868-mhz) - * [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) - * RAK833 +> * [IMST iC880a](https://shop.imst.de/wireless-modules/lora-products/8/ic880a-spi-lorawan-concentrator-868-mhz) +> * [RAK 2245 pi hat](https://store.rakwireless.com/products/rak2245-pi-hat) +> * RAK833 * SX1302 - * [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) with [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) +> * [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) with [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) ### Software From 1cbfd1571bbce5a6249d2ad51c726ad9fbff89ad Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Thu, 24 Jun 2021 15:16:40 +0200 Subject: [PATCH 71/88] Update start_common.sh --- start_common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start_common.sh b/start_common.sh index 9b683cb0..6b1fa858 100644 --- a/start_common.sh +++ b/start_common.sh @@ -23,7 +23,7 @@ fi echo "Server: $TC_URI" # Sanitize TC_TRUST -TC_TRUST=$(echo $TC_TRUST | sed 's/-----BEGIN CERTIFICATE-----/-----BEGIN CERTIFICATE-----\n/' | sed 's/-----END CERTIFICATE-----/\n-----END CERTIFICATE-----/' | sed 's/\n\n/\n/g') +#TC_TRUST=$(echo $TC_TRUST | sed 's/-----BEGIN CERTIFICATE-----/-----BEGIN CERTIFICATE-----\n/' | sed 's/-----END CERTIFICATE-----/\n-----END CERTIFICATE-----/' | sed 's/\n\n/\n/g') # declare map of hardware pins to GPIO on Raspberry Pi declare -a pinToGPIO From 7c62c9fb18382e55f44362314edb39cf771df3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Fri, 25 Jun 2021 10:18:24 +0200 Subject: [PATCH 72/88] Change default LNS server to TTS Community Edition (v3) --- start_common.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/start_common.sh b/start_common.sh index 6b1fa858..7251dd42 100644 --- a/start_common.sh +++ b/start_common.sh @@ -1,18 +1,19 @@ # Defaults to TTN server v2, EU region -TTN_STACK_VERSION=${TTN_STACK_VERSION:-2} +TTN_STACK_VERSION=${TTN_STACK_VERSION:-3} if [ $TTN_STACK_VERSION -eq 2 ]; then TTN_REGION=${TTN_REGION:-"eu"} TC_URI=${TC_URI:-"wss://lns.${TTN_REGION}.thethings.network:443"} - TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/trustid-x3-root.pem.txt")} elif [ $TTN_STACK_VERSION -eq 3 ]; then TTN_REGION=${TTN_REGION:-"eu1"} TC_URI=${TC_URI:-"wss://${TTN_REGION}.cloud.thethings.network:8887"} - TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}")} else echo -e "\033[91mERROR: Wrong TTN_STACK_VERSION value, should be either 2 o 3.\033[0m" balena-idle fi +# Get certificate +TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}")} + # Check configuration if [ "$TC_URI" == "" ] || [ "$TC_TRUST" == "" ] then @@ -22,9 +23,6 @@ fi echo "Server: $TC_URI" -# Sanitize TC_TRUST -#TC_TRUST=$(echo $TC_TRUST | sed 's/-----BEGIN CERTIFICATE-----/-----BEGIN CERTIFICATE-----\n/' | sed 's/-----END CERTIFICATE-----/\n-----END CERTIFICATE-----/' | sed 's/\n\n/\n/g') - # declare map of hardware pins to GPIO on Raspberry Pi declare -a pinToGPIO pinToGPIO=( -1 -1 -1 2 -1 3 -1 4 14 -1 15 17 18 27 -1 22 23 -1 24 10 -1 9 25 11 8 -1 7 0 1 5 -1 6 12 13 -1 19 16 26 20 -1 21) From d10e509bbf35ac06018e63f80426442f4fee6f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Fri, 25 Jun 2021 10:19:40 +0200 Subject: [PATCH 73/88] Fix sanitizing TC_TRUST --- start_common.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/start_common.sh b/start_common.sh index 7251dd42..d564ba14 100644 --- a/start_common.sh +++ b/start_common.sh @@ -14,6 +14,9 @@ fi # Get certificate TC_TRUST=${TC_TRUST:-$(curl --silent "https://letsencrypt.org/certs/{trustid-x3-root.pem.txt,isrgrootx1.pem}")} +# Sanitize TC_TRUST +TC_TRUST=$(echo $TC_TRUST | sed 's/\s//g' | sed 's/-----BEGINCERTIFICATE-----/-----BEGIN CERTIFICATE-----\n/g' | sed 's/-----ENDCERTIFICATE-----/\n-----END CERTIFICATE-----\n/g' | sed 's/\n+/\n/g') + # Check configuration if [ "$TC_URI" == "" ] || [ "$TC_TRUST" == "" ] then From 29962f32919f8ddc2d9375066ae9bb6f193dc153 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 30 Jun 2021 10:38:36 +0200 Subject: [PATCH 74/88] Update README.md --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 75c5ea6c..03b6ef41 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ The Basics™ Station protocol enables the LoRa gateways with a reliable and sec * SX1302 > * [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) with [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) +* SX1303 +> * [RAK 5146](https://store.rakwireless.com/products/wislink-lpwan-concentrator-rak5146) with RAK2287 Pi Hat. + ### Software @@ -62,7 +65,7 @@ If you are a balena CLI expert, feel free to use balena CLI. ### Define your MODEL -The model is defined depending on the version of the concentrator: ```SX1301``` or ```SX1302```. +The model is defined depending on the version of the LoRa concentrator: ```SX1301```, ```SX1302``` and ```SX1303```. In case that your LoRa concentrator is a ```RAK2287``` it is using ```SX1302```. If the concentrator is the ```RAK2245``` or ```iC880a``` it uses the ```SX1301```. It's important to change the balenaCloud Device Variable with the correct ```MODEL```. The default ```MODEL``` on the balena Application is the ```SX1301```. @@ -75,7 +78,7 @@ That enables a fleet of LoRa gateways with both (e.g.) ```RAK2245``` and ```RAK2 From now it's important to facilitate the ```TTN_STACK_VERSION``` that you are going to use: ```3``` (The Things Stack v3) or ```2``` (The Things Network or TTN V2). The default variable is set into ```3```(V3). -Before starting, also check the ```TTN_REGION```. It needs to be changed if your region is not Europe. In case you use version 3, the European version is ```eu1```. Check [here](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html) the LoRa frequencies by country. +Before starting, also check the ```TTN_REGION```. It needs to be changed if your region is not Europe. In case you use version 3, the European version is ```eu1``` by default. Check [here](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html) the LoRa frequencies by country. With these variables ```TTN_REGION``` and ```TTN_STACK_VERSION``` the ```TC_URI``` will be generated automatically. In case that you want to point to another specific ```TC_URI```, feel free to add this Device Variable on the balenaCloud. @@ -152,7 +155,7 @@ Variable Name | Value | Description | Default **`TC_KEY`** | `STRING` | Unique TTN Gateway Key | (Key pasted from TTN console) -#### The Things Network (TTNv2) Specific Variables (V2) +#### (Deprecated) The Things Network (TTNv2) Specific Variables (V2) Remember to copy the The Things Network gateway KEY and ID to configure your board variables on balenaCloud. From 560f6e47c3405ec1a5658bded8ea09419fc9f825 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Wed, 30 Jun 2021 10:40:13 +0200 Subject: [PATCH 75/88] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 03b6ef41..04bbb922 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# LoRa Basics™ Station using balena.io with sx1301 and sx1302 LoRa concentrators +# LoRa Basics™ Station using balena.io with sx1301, sx1302 and sx1303 LoRa concentrators -This project deploys a LoRaWAN gateway with Basics™ Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with sx1301 and sx1302 LoRa concentrators (e.g. RAK833, RAK2245, RAK2287 and IMST iC880a among others). +This project deploys a LoRaWAN gateway with Basics™ Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with sx1301, sx1302 and sx1303 LoRa concentrators (e.g. RAK833, RAK2245, RAK2287, RAK 5146 and IMST iC880a among others). ## Introduction -Deploy a The Things Stack (TTS v3) LoRaWAN gateway running the Basics™ Station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. This project has been tested with The Things Network (TTN v2) and The Things Industries (TTI) as well. +Deploy a The Things Stack (TTS v3) LoRaWAN gateway running the Basics™ Station Semtech Packet Forward protocol. We are using balena.io and RAK to reduce fricition for the LoRa gateway fleet owners. This project has been tested with The Things Network (TTN v2), The Things Stack (TTS v3) and The Things Industries (TTI) as well. The Basics™ Station protocol enables the LoRa gateways with a reliable and secure communication between the gateways and the cloud and it is becoming the standard Packet Forward protocol used by most of the LoRaWAN operators. From 05eab28ea99c2f017540f227b5665648f41d37bf Mon Sep 17 00:00:00 2001 From: Daniel Tedenljung Date: Tue, 17 Aug 2021 20:52:48 +0200 Subject: [PATCH 76/88] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04bbb922..dc7dfa52 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ Initial state: one of more devices connected to TTNv2 stack (The Things Network) Proposed procedure: 1. Create the gateways at TTS using the very same Gateway ID (Gateway EUI) -2. Create a `TC_KEY` variable on each device sith the TTN Gateway Key pasted from the TTI console. +2. Create a `TC_KEY` variable on each device with the TTN Gateway Key pasted from the TTI console. 3. Set the `TTN_STACK_VERSION` variable to 3, either at application level or per device Now you can move them from TTS to TTNv2 back and forth (using the `TTN_STACK_VERSION` variable) as you wish as long as the gateways are defined on both platforms and the `TC_KEY` and `GW_KEY` do not change. From e697d62849e80286e550cbfbb700ac401f0e1c13 Mon Sep 17 00:00:00 2001 From: Ketil Moland Olsen Date: Sat, 16 Oct 2021 13:53:43 +0200 Subject: [PATCH 77/88] Corrected POWER_EN_PIN typo. --- examples/corecell/reset_lgw.sh | 2 +- start_sx1302.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/corecell/reset_lgw.sh b/examples/corecell/reset_lgw.sh index 7732c249..f3c44dc5 100755 --- a/examples/corecell/reset_lgw.sh +++ b/examples/corecell/reset_lgw.sh @@ -12,7 +12,7 @@ # SX1302_RESET_PIN=${GW_RESET_GPIO:-17} -SX1302_POWER_EN_PIN=${GW_RESET_GPIO:-18} +SX1302_POWER_EN_PIN=${GW_POWER_EN_GPIO:-18} WAIT_GPIO() { sleep 0.1 diff --git a/start_sx1302.sh b/start_sx1302.sh index 8ae61028..c244d172 100755 --- a/start_sx1302.sh +++ b/start_sx1302.sh @@ -15,5 +15,6 @@ fi # Set other environment variables export GW_RESET_GPIO=$GW_RESET_GPIO +export GW_POWER_EN_GPIO=$GW_POWER_EN_GPIO ./start-station.sh -l ./lns-ttn From e1771b5b5053739694c3901e3767bb5eb0489502 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Mon, 15 Nov 2021 12:20:22 +0100 Subject: [PATCH 78/88] Test longer logos --- balenacloud.png | Bin 0 -> 5223 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 balenacloud.png diff --git a/balenacloud.png b/balenacloud.png new file mode 100644 index 0000000000000000000000000000000000000000..2024e9da4aa678d0cc8c8cb4078125ca94b438d4 GIT binary patch literal 5223 zcmV-t6qxIYP)(s@bdrAO8@uX z|HwH1`|JPZrvLMbkDaUk)?xqDXgpka|NGhxLS>?{zW?-?|M#~4=c|B}rT_M>|MQIh z@`3;2mjCU)#?ROP^w`wf;s4QA|M|%O^`!sYQ2)<3t-Hqm4O`+m7RM>3 z1L;1Gopdno&>pLL){B5|94?_NgwOUi#qN;o84Nk(G$7=;php~s8t`=Rlc9eR^ld_g6_8LuTm_TJopZPh6S|mvXL0x zzIT@+{qK~&m8P1>gKrE67m3QZ0~v`Zl-N~$zLbN9)1rWbi$w8Mwi3}4bSHH!En6HU z&x*jq10=$n$)QBzYZOZCn(}g!*cHin>g4In+`xk(lt`r#k>A(}eMyKo9DMf+9yWv$ zsZ^Ad*a02=NC`NchQk3N@l8M?_2coqe@&!6R{khST}FuDK_mhce^Dfyoiou2s9Kg~ zH?ynNq?!MJ$l}oiW%4XU@E{>ULWxx3Ak2bzzm3#?(_b(^jh>9(wAHs#eso_1CYE-7 zKT<$3nVloO-2ct4J)f%&ilyZ-GqYJ56;%SPWw z_VI{#{=wWO4lUtm2zP?EeXXf@eI5KC+#0_2vfBX{M zgNz<`q-Wj~h)-^#apU6wVION=qYIgMlB`6Q6avS8vwJOiSPX>qBYBIiZ0qs-l{~=T z*TGq-=1poC>?HRLh>=f72Ee(v0Q6CSxK6O;%I43Y5c){Q_d? ze@20J$CvylKs+WK_kZ~rAu*YTpK`Jv*1;y`$k}O?N(S$u+AAQYL1z;HK92h+KpZ8| z41ug*KNq)~W&rbIg=&(;(p2!8#y$aYwJH6-WMw}V5O5gJ{)3RP?zc%qfZ{W@E&m~l zr4bNBwT&^E$!x?&10wlLtK8#Iq88RjK%~f9~09foL@ToQ)3%#6$?kK=Eq1%8u@Sz6hrlXe4>F5eVze zQk;3)wn-i&2ndJbX%-#)SuuH*a4=s+sEN_kDf>zw#{GJ(n#t8q<`03@9_EMbcKdK% zQhyx;L}~42NBe7^x=fAr;Ylu6Z?6LhMP1q093M~u?P-EPw(lyuCjnRZ^FSb0Ps^WI zSI5iNYST~HDC=(7xwv?l{=9dGIv5BCi7OmRJOw8$%?mtfnsg94uL0uWL^ljwPwP7T zuhBj9ImL}}PB(}OZI_%y9SLW^{eWmJ>a40!IFYF%55dA|?TvQ`VGO zdCG4D0(QQL1D(m0zmWg{XCAD3Vi;cmL_2N7Ii-!Na)D!=F?7CEVE|d0!=ZzN*UO(Pw@@j3oCBKqo64=!zttHTJnxB%@vwfT)RX44m6{8-aknpmK*G%y!gB0PP9~ z51eP&8i0exJU8&Yo!V=i}P zQB`#10kVlI2tYiuF$Yu6!o@vrK9Dm}17RzM0GK~HBVn<*tpEfr%L4&NOKz%IqyOs* zgzGm@C#}1RH@XDo40|#m_S_PPcs1i0EN8sBlC55J6~)qpbqFBFUgF#`8SdIAK*S4a z&p~v_UX2TiuIPn@5(qAWFukc;>xEnFLI5a%XkMtV$Sa0ecpyfBNyi`{oI$VQhL&4Dq@dDBG8$xqNgObodJO?MCgMn~b!pm{C;KS&$MNH0LZ4CrDp-xE2 zo$7Rf^BQ9T8(1_={!VWKqR$^EEgV8;j!6Q7JAm62&by3zVnNm*{vQDdmV=PII8lc? zdn+Fx@-Mza2(F0N2n&S0VQ0f8Ae>MFPb*inUvv(l$Z)?72)$Q;bIwfFFzET!*-nWP z`xKVcyO~U;&@*^Oe1TZA@k_(`Kn5Oy1pw?20uZ`U$Yi=)1Zxavw-*e}w9$hOFHo|K+AY~=lpY4WEB6E9fyM;7UhSir>vEjbG;lQ@h;%yl;1pcs=*6Gz z(r}~7x>6X7QG?@Ln(GP=1Q#Qi!kVVPyg-b^8G-XJ7kN}BTLEz=HYT+e4hW|X&PBEy z{{vo7ADYLiJmxEa=#{w$vT?|+Y3$?Y^b@1Z`H@DQ1&e+_lnq*wJH~>3tk2OW3<$kT zBa1b)1_lXe`m8G_Tuk~hF`0-o}XLC+%$o1XbA@d=P=-0 z^!^UERud*2p@482M5bv3dAe|an)Re!{MsG}&LF#*r=>5t^nvfwQIu#_g4=)M(6wo^WsqKyarh@N6)7fZ!*tB*eFmxrT8jC=?JQ-nO(b zqjrst4#NTAY=&~HKWjzzzxLE8U9~k3Vj{;8y$lU^wAOS~>vG8x(ufZbX%oZtu0IvpuIemU2x@4vY?Y#^K1Q*lrxyvVxlaN3-ZMr1f zyCLSpcWr!IAoPs)J2DPvv`!3C(z~=!4V+~>6vS^8$H!k$AbLV#l1wQ`C(8t|x~IKT zK{3mC0}C;sMqUg{e-gt1F5JIE0bz6V6~TqE3|V*}H0&$HUj8u8{XxBQAbS{eofzj@TSAhG6F<@N6*2K-~EZA#1wg z0uTy_ChN|Va8wrkZUKY_&T;jix$L&7>vF)Cu7_uro}yp_f2jsyKnAd@5E*M1NCJdj z7u&}s0RvI$sY|(95bNO+REB(*iVOtx4M5tK&zy!ke+dP|gqoG26yt_i%TNtAo;n3i zjJE?qjwq4pWE@J|C@Abc^)6~4Sm2uWhTMh*T4NzseVoh?5Zv_N)8moXJTLYoo%5q5TIW)}=y`WLRBc=qR z(e+7M^9l#VC-*NB-s;Llacr!F#1xC)UzwP)&S?wM9tax7p`3UqAX*d%Pagf^H9%;l z+o^khhp{~n%3(vvJTfh$pP|1ol zZ90T*`ucrSrOEMPUfHbQy02#4IL+&VLSsIx-+JM3svn)Xt?G5JNOr8p&TM2^kIu5<}>U`HnJ% zVCUJ%L?~{7Uh>-|+)w17^2#rU$P(7Ja2YEKL``grE4dvIm6$lW{$n8AF_+cI;JJe{ z1tGHxX-0@tk}^kPP)YI`>8ign?hG;<5R^?%o(pQNm}Nls%8hu(Q>VqBI25tVKv4fI zk0IS|1p;Onng~RbHYPi;ktQ7`91z-@13_04crAGAOX!GyQlLY3 z10vQVfGKw0o+yE^xl`i_?fDJa#DE0kAw&zqrvC13Oa_F>1siOdiGW~PE@`dpSmy5C zfJmpkCzm7yQQELA4LT-fus+fvja%an|31iygx2ga< zE%jt7X--(2r!1wE0t14}aE~M)@@x_-rn%S}$GZceIJxAq$4-I_Yh3rNdJKZsGU&WB zz3D!UkU-G23~yLj_5q^FC-J}wyL$7-0uLk&>{-j;vdvsr%A5`HL_gVB(^56rMKCPLFgnS0M9s1rKQ@n{m zcZLe}$#p*B+cQo0FJF%Uu@dc-_cl`*h=a4ho4z*!0cN%y2oA5xyeA-JF%8IoNtW}WN1;QPl zs{1lVeuF6FmnNZrh^@lim+_fB);P#SYy!e$1|r-urg{%^LqUX5mA0S^RHgLZx*xEX zL8_|ntkL6hR%Qzz8p`(c_5@OK8A_yhNb_A~w2E+)D{M;w~3U4mRMVq~Zla@kBhJ zJ(IdLL(bmN8AL=d5ax`%JR^0ZIxkFB^x)EeFW_jL^bF>S;f!#gdPYPEPAj+oAZ@rC z;rl(ujqBtFi%;%fdhbxGY6yW}TJKfG#6&5MD$1KB2dH`dlUO<@+$IEj?94$220FG9 z2zbf0Dsn&%%wkKvY_jw&eIe0pKZ#H3aOyrwRpp(}pt5rOgZq!Lc460qi4HKeI~cjj z4=!asBYEcg4xJz%fcBev0(xS@dsOCqB-a!)+L>niF?B`bPyjZEsuAZJ1G(cH4k>_iBw7fc> z!OGKGE32vt)x4i+=uz5JCpneR63N41KQB8k#memb_zrEz_8gWo5zfmIek&teUm#5G zY4{Eg8z!B5EzA0Y=R|F+Y&j3yx5GVbKe(++;r%Jev+s&1$Oj0~TR0Bm>lVK;(#Mp2 zDZOv&Z012i2?VIjhSJOVzWzVF4IMOikM+O3zzr|O8M{oDtHC^AxeuIC}vj_yx&W9cx zqW6FAn5@U7gv7xwny2D{0KgkOMBZW-<%ANFl^`$S;(#!VzeMwpieCJ^v$Aheo>0Q| z8x#nj{XUbtMf8g2U6wbL_ywa&a-$9a-{s&Tbra#R)3P3iawy@v+ZBG3H!I#3zz>7B z!$jHvc|(ceuiwt+-(?&U!|2V!OV;NhXC*v9z*sU09`;Q6qZG9g5)e`Fu%EKO(pN7EKqQ8@(W>Ttiex2tAfi>Q zz1E`}T{0kG@DRn4d#(H}3?(oSDfZ&{Nc*e&m&?Qu{@41E`X^e&iUehUb|w|p(RJ`m hS& Date: Mon, 15 Nov 2021 12:21:16 +0100 Subject: [PATCH 79/88] Test longer logos! --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index 318bdd9e..7ff21db4 100644 --- a/balena.yml +++ b/balena.yml @@ -19,7 +19,7 @@ assets: type: blob.asset data: url: >- - https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png + https://raw.githubusercontent.com/balenalabs/basicstation/master/balenacloud.png data: applicationEnvironmentVariables: - GW_GPS: false From ce3f2d8b1b8af1817b18cdb626c06eb4fca0f7fa Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 16 Nov 2021 11:13:18 +0100 Subject: [PATCH 80/88] Update balena.yml --- balena.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balena.yml b/balena.yml index 7ff21db4..318bdd9e 100644 --- a/balena.yml +++ b/balena.yml @@ -19,7 +19,7 @@ assets: type: blob.asset data: url: >- - https://raw.githubusercontent.com/balenalabs/basicstation/master/balenacloud.png + https://raw.githubusercontent.com/balenalabs/basicstation/master/logo.png data: applicationEnvironmentVariables: - GW_GPS: false From 73ba859db6f562bc5f7350abf374e4771681b9e8 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Tue, 16 Nov 2021 11:13:34 +0100 Subject: [PATCH 81/88] Delete balenacloud.png --- balenacloud.png | Bin 5223 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 balenacloud.png diff --git a/balenacloud.png b/balenacloud.png deleted file mode 100644 index 2024e9da4aa678d0cc8c8cb4078125ca94b438d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5223 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 hS& Date: Thu, 16 Dec 2021 15:44:22 +0100 Subject: [PATCH 82/88] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dc7dfa52..d68db6ef 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # LoRa Basics™ Station using balena.io with sx1301, sx1302 and sx1303 LoRa concentrators -This project deploys a LoRaWAN gateway with Basics™ Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with sx1301, sx1302 and sx1303 LoRa concentrators (e.g. RAK833, RAK2245, RAK2287, RAK 5146 and IMST iC880a among others). +This project deploys a LoRaWAN gateway with Basics™ Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with sx1301, sx1302 and sx1303 SPI LoRa concentrators (e.g. RAK833, RAK2245, RAK2287, RAK5146, Seeed WM1302 and IMST iC880a among others). ## Introduction @@ -17,7 +17,9 @@ The Basics™ Station protocol enables the LoRa gateways with a reliable and sec * Raspberry Pi 3/4 or [balenaFin](https://www.balena.io/fin/) * SD card in case of the RPi 4 -#### LoRa Concentrators +#### LoRa Concentrators (SPI) + +Disclaimer: At the moment the basicstation project is not compatible with USB LoRa concentrators. Contributions open :) * SX1301 > * [IMST iC880a](https://shop.imst.de/wireless-modules/lora-products/8/ic880a-spi-lorawan-concentrator-868-mhz) @@ -26,6 +28,7 @@ The Basics™ Station protocol enables the LoRa gateways with a reliable and sec * SX1302 > * [RAK 2287 Concentrator](https://store.rakwireless.com/products/rak2287-lpwan-gateway-concentrator-module) with [RAK 2287 Pi Hat](https://store.rakwireless.com/products/rak2287-pi-hat) +> * [Seeed WM1302](https://www.seeedstudio.com/WM1302-LoRaWAN-Gateway-Module-SPI-EU868-p-4889.html) with the Pi Hat (this model is compatible with the RAK2287 Pi Hat as well). * SX1303 > * [RAK 5146](https://store.rakwireless.com/products/wislink-lpwan-concentrator-rak5146) with RAK2287 Pi Hat. From 582b9548b5b24d0019810a6a836ec55199d7b924 Mon Sep 17 00:00:00 2001 From: mpous Date: Fri, 14 Jan 2022 00:11:48 +0100 Subject: [PATCH 83/88] Update mbedTLS dependency to version 2.7.5. Related to lorabasics#142 --- deps/mbedtls/prep.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/mbedtls/prep.sh b/deps/mbedtls/prep.sh index 2875cd72..4f774f04 100755 --- a/deps/mbedtls/prep.sh +++ b/deps/mbedtls/prep.sh @@ -30,7 +30,7 @@ set -e cd $(dirname $0) if [[ ! -d git-repo ]]; then - git clone -b mbedtls-2.6 --single-branch --depth 1 https://github.com/ARMmbed/mbedtls.git git-repo + git clone -b mbedtls-2.7.5 --single-branch --depth 1 https://github.com/ARMmbed/mbedtls.git git-repo fi if [[ -z "$platform" ]] || [[ -z "$variant" ]]; then From f557250bb28f3d2b95187c2118ac01ef3c6b1c32 Mon Sep 17 00:00:00 2001 From: mpous Date: Fri, 21 Jan 2022 15:36:29 +0100 Subject: [PATCH 84/88] adding Pi Zero without Ethernet mac address support --- README.md | 6 ++++-- docker-compose.yml | 21 +++++++++++++++++++++ setup.gmk | 2 ++ src-linux/sys_linux.c | 8 ++++++-- start.sh | 10 +++++++++- 5 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 docker-compose.yml diff --git a/README.md b/README.md index d68db6ef..04e8ef14 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ The Basics™ Station protocol enables the LoRa gateways with a reliable and sec ### Hardware -* Raspberry Pi 3/4 or [balenaFin](https://www.balena.io/fin/) -* SD card in case of the RPi 4 +* Raspberry Pi 0, 3/4 or [balenaFin](https://www.balena.io/fin/) +* SD card in case of the RPi 0/3/4 #### LoRa Concentrators (SPI) @@ -146,6 +146,8 @@ Variable Name | Value | Description | Default **`TC_TRUST`** | `STRING` | Certificate for the server | Automatically retrieved from LetsEncryt based on the `TTN_STACK_VERSION` value **`MODEL`** | `STRING` | ```SX1301``` or ```SX1302``` | ```SX1301``` **`TC_URI`** | `STRING` | basics station TC URI to get connected. | +**`EUI_ADDRESS`** | `STRING` | In case you use Raspberry Pi Zero without `eth0` you can use this to generate the `EUI` from `wlan0` instead of another network interface. You will need to add `wlan0` | + #### The Things Stack (TTS) Specific Variables (V3) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..6c37b109 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +version: 2 + +services: + + basicstation: + build: . + container_name: basicstation + restart: unless-stopped + privileged: true + network_mode: host # required to read main interface MAC instead of virtual one + environment: + MODEL: "SX1301" + GW_GPS: "false" + GW_RESET_GPIO: 17 + GW_ENABLE_GPIO: 0 + TTN_STACK_VERSION: 3 + TTN_REGION: "eu1" + #TC_URI: # uses TTN server by default, based on the TTN_STACK_VERSION and TTN_REGION variables + #TC_TRUST: # uses TTN certificates by default + TC_KEY: + #DEVICE: # required if you use a Pi Zero W or Pi Zero 2 W diff --git a/setup.gmk b/setup.gmk index c0c7e428..a25e74df 100644 --- a/setup.gmk +++ b/setup.gmk @@ -45,9 +45,11 @@ ARCH.linux.default = x86_64-linux-gnu ARCH.linuxV2.default = x86_64-linux-gnu ARCH.linuxpico.default = x86_64-linux-gnu ARCH.corecell.default = arm-linux-gnueabihf +ARCH.corecell.rpi = arm-linux-gnueabihf ARCH.corecell.armv7hf = arm-linux-gnueabihf ARCH.corecell.aarch64 = aarch64-linux-gnu ARCH.rpi.default = arm-linux-gnueabihf +ARCH.rpi.rpi = arm-linux-gnueabihf ARCH.rpi.armv7hf = arm-linux-gnueabihf ARCH.rpi.aarch64 = aarch64-linux-gnu ARCH.kerlink.default = arm-klk-linux-gnueabi diff --git a/src-linux/sys_linux.c b/src-linux/sys_linux.c index 5b637c9e..019095f4 100644 --- a/src-linux/sys_linux.c +++ b/src-linux/sys_linux.c @@ -204,9 +204,12 @@ static void findDefaultEui () { if( ifc[0] != 0 ) { if( strncmp(ifc, "eth", 3) == 0 && strncmp(dname, "eth", 3) != 0 ) continue; // eth trumps other devices + // in case there is no eth0 + if( strncmp(ifc, "wla", 3) == 0 && strncmp(dname, "wla", 3) != 0 ) + continue; // wlan trumps other devices // Otherwie choose alphabetically lowest - unless eth replaces something else if( !((strncmp(ifc, "eth", 3) == 0) ^ (strncmp(dname, "eth", 3) == 0)) - && strcmp(ifc, dname) <= 0 ) + && strcmp(ifc, dname) > 0 ) continue; // not lower } strcpy(ifc, dname); @@ -219,6 +222,7 @@ static void findDefaultEui () { protoEUI = eui; rt_free((void*)protoEuiSrc); protoEuiSrc = rt_strdup(path); + LOG(MOD_SYS|INFO, "findDefaultEui -> protoEuiSrc %s - protoEUI %lu", protoEuiSrc, protoEUI); } } @@ -366,7 +370,7 @@ void sys_ini () { logfile.path==NULL ? "stderr" : logfile.path, logfile.size, logfile.rotate); LOG(MOD_SYS|INFO, "Station Ver : %s", CFG_version " " CFG_bdate); LOG(MOD_SYS|INFO, "Package Ver : %s", sys_version()); - LOG(MOD_SYS|INFO, "proto EUI : %:E\t(%s)", protoEUI, protoEuiSrc); + LOG(MOD_SYS|INFO, "proto EUI(x) : %:E\t(%s)", protoEUI, protoEuiSrc); LOG(MOD_SYS|INFO, "prefix EUI : %:E\t(%s)", prefixEUI, prefixEuiSrc); LOG(MOD_SYS|INFO, "Station EUI : %:E", sys_eui()); LOG(MOD_SYS|INFO, "Station home: %s\t(%s)", homeDir, homeDirSrc); diff --git a/start.sh b/start.sh index 25ebada1..dd5c8328 100644 --- a/start.sh +++ b/start.sh @@ -1,7 +1,15 @@ #!/usr/bin/env bash TAG_KEY="EUI" -TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1fffe\2#g') + +if [ -z ${EUI_ADDRESS} ] ; + then + TTN_EUI=$(cat /sys/class/net/eth0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1fffe\2#g') + else + echo "Using DEVICE: $EUI_ADDRESS" + TTN_EUI=$(cat /sys/class/net/wlan0/address | sed -r 's/[:]+//g' | sed -e 's#\(.\{6\}\)\(.*\)#\1fffe\2#g') +fi + echo "Gateway EUI: $TTN_EUI" From 94ebc8981f16b247b85507eb453267d604bcc801 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 21 Jan 2022 15:48:27 +0100 Subject: [PATCH 85/88] Update docker-compose.yml --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6c37b109..65905ae8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,4 +18,4 @@ services: #TC_URI: # uses TTN server by default, based on the TTN_STACK_VERSION and TTN_REGION variables #TC_TRUST: # uses TTN certificates by default TC_KEY: - #DEVICE: # required if you use a Pi Zero W or Pi Zero 2 W + #EUI_ADDRESS: # required if you use a Pi Zero W or Pi Zero 2 W From d54fa2fee0951dded8b47a9bfe73a13cb7e5d942 Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Wed, 26 Jan 2022 11:32:10 +0100 Subject: [PATCH 86/88] Setting label io.balena.features.balena-api to ensure BALENA_API_KEY is injected fixes #49 --- .gitignore | 2 ++ docker-compose.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 4668c4b5..ea515a7c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +# IDE +.vscode deps/.DS_Store .DS_Store diff --git a/docker-compose.yml b/docker-compose.yml index 65905ae8..75723368 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,3 +19,5 @@ services: #TC_TRUST: # uses TTN certificates by default TC_KEY: #EUI_ADDRESS: # required if you use a Pi Zero W or Pi Zero 2 W + labels: + io.balena.features.balena-api: '1' From d450b5dc69a8e80dacb86c8c3bb2825f7baf7ce3 Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Mon, 4 Mar 2024 14:09:34 +0100 Subject: [PATCH 87/88] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 04e8ef14..bc34ed9d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # LoRa Basics™ Station using balena.io with sx1301, sx1302 and sx1303 LoRa concentrators +## This project is deprecated! You can see the balena basicstation updated here + +[https://github.com/xoseperez/basicstation](https://github.com/xoseperez/basicstation) + +--- + This project deploys a LoRaWAN gateway with Basics™ Station Packet Forward protocol with balena. It runs on a Raspberry Pi (3/4) or balenaFin with sx1301, sx1302 and sx1303 SPI LoRa concentrators (e.g. RAK833, RAK2245, RAK2287, RAK5146, Seeed WM1302 and IMST iC880a among others). From 348cd2d70221abec29039b253bbd61428ec9a03f Mon Sep 17 00:00:00 2001 From: Marc Pous Date: Fri, 27 Dec 2024 16:24:31 +0100 Subject: [PATCH 88/88] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc34ed9d..b81b3457 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## This project is deprecated! You can see the balena basicstation updated here -[https://github.com/xoseperez/basicstation](https://github.com/xoseperez/basicstation) +[https://github.com/xoseperez/basicstation](https://github.com/xoseperez/basicstation-docker) ---