Compare commits
1 Commits
master
...
feature/ca
Author | SHA1 | Date | |
---|---|---|---|
|
094756c414 |
@ -1,44 +1,40 @@
|
|||||||
# Environment Variables
|
#Environment Variables
|
||||||
## Required global variables
|
##Required global variables
|
||||||
* GW_ID required
|
* GW_ID required
|
||||||
* GW_KEY required
|
* GW_KEY required
|
||||||
* This gateway ID and gateway Key for TTN will be used to fetch the gateway's information form the TTN console. When SERVER_TTN is true, this will also be used to conenct and forward packets to TTN.
|
This gateway ID and gateway Key for TTN will be used to fetch the gateway's information form the TTN console. When SERVER_TTN is true, this will also be used to conenct and forward packets to TTN.
|
||||||
|
|
||||||
## Optional global variables
|
##Optional global variables
|
||||||
* GW_EUI - by default an EUI will be generated from the Raspberry Pi's ethernet MAC address.
|
* GW_CONTACT_EMAIL optional - default an empty string
|
||||||
* The unique identifier for this gateway. It is used in LoRaWAN networks to identify where the packet was received and to address where a downlink packet needs to be sent from.
|
The gateway owner's contact information. Will be overridden by the value from the TTN console.
|
||||||
* GW_CONTACT_EMAIL - default an empty string
|
|
||||||
* The gateway owner's contact information. Will be overridden by the value from the TTN console.
|
|
||||||
* GW_DESCRIPTION optional - default an empty string
|
* GW_DESCRIPTION optional - default an empty string
|
||||||
* A description of this gateway. Will be overridden by the value from the TTN console.
|
A description of this gateway. Will be overridden by the value from the TTN console.
|
||||||
* GW_RESET_PIN - default 22
|
* GW_RESET_PIN - default 22
|
||||||
* The physical pin number on the Raspberry Pi to which the concentrator's reset is connected. See the [README](README.md) file for a description and a list of common values.
|
The physical pin number on the Raspberry Pi to which the concentrator's reset is connected. See the [README](README.md) file for a description and a list of common values.
|
||||||
* GW_GPS optional - default False
|
* GW_GPS optional - default False
|
||||||
* If true, use the hardware GPS.
|
* If true, use the hardware GPS.
|
||||||
* If false,
|
* If false,
|
||||||
* use either fake gps if a location was configured in the TTN console,
|
use either fake gps if a location was configured in the TTN console,
|
||||||
* otherwise try using fake gps with the reference location as set via environment variables,
|
otherwise try using fake gps with the reference location as set via environment variables,
|
||||||
* otherwise don't send coordinates.
|
otherwise don't send coordinates.
|
||||||
* GW_GPS_PORT optional - default /dev/ttyAMA0
|
* GW_GPS_PORT optional - default /dev/ttyAMA0
|
||||||
* The UART to which the hardware GPS is connected to.
|
The UART to which the hardware GPS is connected to.
|
||||||
* GW_REF_LATITUDE optional - default 0
|
* GW_REF_LATITUDE optional - default 0
|
||||||
* The latitude to use for fake gps if the coordinates are not set in the TTN console.
|
The latitude to use for fake gps if the coordinates are not set in the TTN console.
|
||||||
* GW_REF_LONGITUDE optional - default 0
|
* GW_REF_LONGITUDE optional - default 0
|
||||||
* The longitude to use for fake gps if the coordinates are not set in the TTN console.
|
The longitude to use for fake gps if the coordinates are not set in the TTN console.
|
||||||
* GW_REF_ALTITUDE optional - default 0
|
* GW_REF_ALTITUDE optional - default 0
|
||||||
* The altitude to use for fake gps if the coordinates are not set in the TTN console.
|
The altitude to use for fake gps if the coordinates are not set in the TTN console.
|
||||||
* GW_LOGGER optional - default false
|
|
||||||
* Write a line to the terminal whenever a packet is received. ex: `08:54:37 INFO: [stats] received packet with valid CRC from mote: 26011C51 (fcnt=7)`
|
|
||||||
* GW_FWD_CRC_ERR optional - default false
|
* GW_FWD_CRC_ERR optional - default false
|
||||||
* Forward packets with an invalid CRC.
|
Forward packets with an invalid CRC.
|
||||||
* GW_FWD_CRC_VAL optional - default true.
|
* GW_FWD_CRC_VAL optional - default true.
|
||||||
* Forward packets with a valid CRC.
|
Forward packets with a valid CRC.
|
||||||
* GW_ANTENNA_GAIN optional - default 0.
|
* GW_ANTENNA_GAIN optional - default 0.
|
||||||
* Set this to the dBd gain of your antenna. The dBd value is the dBi value minus 2.15dB, ie. dBd = dBi-2.15. This is used to reduce the TX power of the concentrator to stay within the legal limits.
|
Set this to the dBd gain of your antenna. The dBd value is the dBi value minus 2.15dB, ie. dBd = dBi-2.15. This is used to reduce the TX power of the concentrator to stay within the legal limits.
|
||||||
* FREQ_PLAN_URL optional - default `https://account.thethingsnetwork.org/api/v2/frequency-plans/EU_863_870`
|
* CAYENNE_SCRIPT optional
|
||||||
* The URL where the base configuration file and frequency plan should be downloaded from. This is overwritten by the URL given by the TTN account server when using the TTN gateway connector protocol.
|
When this variable is set to a Raspberry Pi Cayenne monitoring script, the script will be downloaded and executed. This allows monitoring of your gateway on Cayenne.
|
||||||
|
|
||||||
## Server variables
|
##Server variables
|
||||||
All server variables are optional, but when a server is enabled, it is recommended to set all variables to configure it completely.
|
All server variables are optional, but when a server is enabled, it is recommended to set all variables to configure it completely.
|
||||||
* SERVER_TTN optional - default true
|
* SERVER_TTN optional - default true
|
||||||
Should the gateway connect to the TTN backend
|
Should the gateway connect to the TTN backend
|
||||||
@ -70,35 +66,11 @@ All server variables are optional, but when a server is enabled, it is recommend
|
|||||||
* SERVER_3_GWKEY
|
* SERVER_3_GWKEY
|
||||||
* SERVER_3_DOWNLINK - default false
|
* SERVER_3_DOWNLINK - default false
|
||||||
|
|
||||||
As long as `SERVER_TTN` is set to false, you can also:
|
|
||||||
* SERVER_0_ENABLED optional - default false
|
|
||||||
* SERVER_0_TYPE - default "semtech"
|
|
||||||
* SERVER_0_ADDRESS
|
|
||||||
* SERVER_0_PORTUP - only when using type semtech
|
|
||||||
* SERVER_0_PORTDOWN - only when using type semtech
|
|
||||||
* SERVER_0_GWID
|
|
||||||
* SERVER_0_GWKEY
|
|
||||||
* SERVER_0_DOWNLINK - default false
|
|
||||||
|
|
||||||
## Example for using only legacy forwarder
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
| ----------------- | ----- |
|
|
||||||
| SERVER_TTN | false |
|
|
||||||
| SERVER_1_ADDRESS | bridge.eu.thethings.network |
|
|
||||||
| SERVER_1_ENABLED | true |
|
|
||||||
| SERVER_1_PORTDOWN | 1700 |
|
|
||||||
| SERVER_1_PORTUP | 1700 |
|
|
||||||
| FREQ_PLAN_URL | https://account.thethingsnetwork.org/api/v2/frequency-plans/EU_863_870 |
|
|
||||||
| GW_REF_LATITUDE | -33.1 |
|
|
||||||
| GW_REF_LONGITUDE | 18.9 |
|
|
||||||
| GW_REF_ALTITUDE | 190 |
|
|
||||||
|
|
||||||
## Note about boolean values
|
## Note about boolean values
|
||||||
|
|
||||||
Use `true` and `false` as lower case words to enable or disable features via environment variables. Any other format will not be interpreted correctly.
|
Use `true` and `false` as lower case words to enable or disable features via environment variables. Any other format will not be interpreted correctly.
|
||||||
|
|
||||||
# Logal debugging
|
#Logal debugging
|
||||||
```
|
```
|
||||||
docker run --device /dev/ttyAMA0:/dev/ttyAMA0 --device /dev/mem:/dev/mem --privileged -e GW_TYPE="imst-ic880a-spi" -e GW_DESCRIPTION="test gateway" -e GW_CONTACT_EMAIL="" -e GW_ID="" -e GW_KEY="" newforwarder
|
docker run --device /dev/ttyAMA0:/dev/ttyAMA0 --device /dev/mem:/dev/mem --privileged -e GW_TYPE="imst-ic880a-spi" -e GW_DESCRIPTION="test gateway" -e GW_CONTACT_EMAIL="" -e GW_ID="" -e GW_KEY="" newforwarder
|
||||||
|
|
||||||
|
@ -1,29 +1,18 @@
|
|||||||
FROM resin/%%RESIN_MACHINE_NAME%%-debian:latest AS buildstep
|
FROM resin/%%RESIN_MACHINE_NAME%%-buildpack-deps
|
||||||
|
|
||||||
|
# Enable systemd, as Resin requires this
|
||||||
|
ENV INITSYSTEM on
|
||||||
|
|
||||||
|
# Make the hardware type available as a runtime env var
|
||||||
|
ENV RESIN_ARCH %%RESIN_ARCH%%
|
||||||
|
ENV RESIN_MACHINE_NAME %%RESIN_MACHINE_NAME%%
|
||||||
|
|
||||||
|
# Copy the build and run environment
|
||||||
|
COPY . /opt/ttn-gateway/
|
||||||
WORKDIR /opt/ttn-gateway/
|
WORKDIR /opt/ttn-gateway/
|
||||||
|
|
||||||
# downloading utils
|
# Build the gateway (or comment this out if debugging on-device)
|
||||||
RUN apt-get update && \
|
RUN ./dev/build.sh && rm -rf ./dev
|
||||||
apt-get install wget build-essential libc6-dev git pkg-config protobuf-compiler libprotobuf-dev libprotoc-dev automake libtool autoconf python-dev python-rpi.gpio
|
|
||||||
|
|
||||||
COPY dev dev
|
# Start it up
|
||||||
RUN ./dev/build.sh
|
CMD ["sh", "-c", "./run.py"]
|
||||||
|
|
||||||
FROM resin/%%RESIN_MACHINE_NAME%%-debian:latest
|
|
||||||
|
|
||||||
WORKDIR /opt/ttn-gateway
|
|
||||||
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install python-rpi.gpio && \
|
|
||||||
apt-get clean && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
COPY --from=buildstep /opt/ttn-gateway/mp_pkt_fwd .
|
|
||||||
COPY --from=buildstep /usr/local/lib/libpaho-embed-* /usr/lib/
|
|
||||||
COPY --from=buildstep /usr/lib/libttn* /usr/lib/
|
|
||||||
|
|
||||||
COPY run.py ./
|
|
||||||
COPY start.sh ./
|
|
||||||
|
|
||||||
# run when container lands on device
|
|
||||||
CMD ["bash", "start.sh"]
|
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
FROM resin/%%RESIN_MACHINE_NAME%%-debian:latest AS buildstep
|
|
||||||
|
|
||||||
# downloading utils
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install wget build-essential libc6-dev git pkg-config protobuf-compiler libprotobuf-dev libprotoc-dev automake libtool autoconf python-dev python-rpi.gpio
|
|
||||||
|
|
||||||
WORKDIR /etc
|
|
||||||
|
|
||||||
# versions
|
|
||||||
ENV NODE_EXPORTER_VERSION 0.12.0
|
|
||||||
ENV DIST_ARCH linux-armv7
|
|
||||||
RUN wget https://github.com/prometheus/node_exporter/releases/download/${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.${DIST_ARCH}.tar.gz \
|
|
||||||
&& tar xvfz node_exporter-${NODE_EXPORTER_VERSION}.${DIST_ARCH}.tar.gz \
|
|
||||||
&& rm node_exporter-${NODE_EXPORTER_VERSION}.${DIST_ARCH}.tar.gz
|
|
||||||
|
|
||||||
COPY gwexporter.tgz /opt/ttn-gateway/gwexporter.tgz
|
|
||||||
WORKDIR /opt/gwexporter
|
|
||||||
RUN tar xvzf /opt/ttn-gateway/gwexporter.tgz
|
|
||||||
RUN wget https://nodejs.org/dist/v8.8.1/node-v8.8.1-linux-armv6l.tar.gz \
|
|
||||||
&& tar xvzf node-v8.8.1-linux-armv6l.tar.gz \
|
|
||||||
&& mv node-v8.8.1-linux-armv6l/* . \
|
|
||||||
&& rm -rf node-v8.8.1-linux-armv6l
|
|
||||||
|
|
||||||
WORKDIR /opt/ttn-gateway/
|
|
||||||
COPY dev dev
|
|
||||||
RUN ./dev/build.sh
|
|
||||||
|
|
||||||
FROM resin/%%RESIN_MACHINE_NAME%%-debian:latest
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install python-rpi.gpio && \
|
|
||||||
apt-get clean && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Enable systemd
|
|
||||||
ENV INITSYSTEM on
|
|
||||||
|
|
||||||
# versions
|
|
||||||
ENV NODE_EXPORTER_VERSION 0.12.0
|
|
||||||
ENV DIST_ARCH linux-armv7
|
|
||||||
|
|
||||||
WORKDIR /etc
|
|
||||||
COPY --from=buildstep /etc/node_exporter-${NODE_EXPORTER_VERSION}.${DIST_ARCH} .
|
|
||||||
|
|
||||||
WORKDIR /opt/gwexporter
|
|
||||||
COPY --from=buildstep /opt/gwexporter .
|
|
||||||
|
|
||||||
WORKDIR /opt/ttn-gateway
|
|
||||||
COPY --from=buildstep /opt/ttn-gateway/mp_pkt_fwd .
|
|
||||||
COPY --from=buildstep /usr/local/lib/libpaho-embed-* /usr/lib/
|
|
||||||
COPY --from=buildstep /usr/lib/libttn* /usr/lib/
|
|
||||||
COPY run.py run.py
|
|
||||||
|
|
||||||
WORKDIR /
|
|
||||||
|
|
||||||
COPY start.sh.metering start.sh
|
|
||||||
|
|
||||||
# run when container lands on device
|
|
||||||
CMD ["bash", "start.sh"]
|
|
28
README.md
28
README.md
@ -1,8 +1,6 @@
|
|||||||
# Introduction
|
# Introduction
|
||||||
This resin.io setup is based on the [Multi-protocol Packet Forwarder by Jac Kersing](https://github.com/kersing/packet_forwarder/tree/master/mp_pkt_fwd).
|
This resin.io setup is based on the [Multi-protocol Packet Forwarder by Jac Kersing](https://github.com/kersing/packet_forwarder/tree/master/mp_pkt_fwd).
|
||||||
|
|
||||||
An alternative guide to use this Resin.io setup can be found in the official TTN documentation at: https://www.thethingsnetwork.org/docs/gateways/rak831/
|
|
||||||
|
|
||||||
## Difference between Poly-packet-forwarder and Multi-protocol-packet-forwarder
|
## Difference between Poly-packet-forwarder and Multi-protocol-packet-forwarder
|
||||||
mp-pkt-fwd uses the new protocolbuffers-over-mqtt-over-tcp protocol for gateways, as defined by TTN and used by the TTN kickstarter gateway. Using this protcol the gateway is authenticated, which means it is registered under a specific user and can thus be trusted. Because it uses TCP, the chance of packet loss is much lower than with the previous protocol that used UDP. Protocolbuffers packs the data in a compact binary mode into packets, using much less space than the plaintext json that was previously used. It should therefore consume less bandwidth.
|
mp-pkt-fwd uses the new protocolbuffers-over-mqtt-over-tcp protocol for gateways, as defined by TTN and used by the TTN kickstarter gateway. Using this protcol the gateway is authenticated, which means it is registered under a specific user and can thus be trusted. Because it uses TCP, the chance of packet loss is much lower than with the previous protocol that used UDP. Protocolbuffers packs the data in a compact binary mode into packets, using much less space than the plaintext json that was previously used. It should therefore consume less bandwidth.
|
||||||
|
|
||||||
@ -16,7 +14,6 @@ Currently any Raspberry Pi with one of the following gateway boards, communicati
|
|||||||
* [IMST iC880A-SPI](http://webshop.imst.de/ic880a-spi-lorawan-concentrator-868mhz.html). Preferable configured as described [by TTN-ZH](https://github.com/ttn-zh/ic880a-gateway/wiki). You **do not** need to follow the **Setting up the software** step, as the setup scripts in this repository does it for you.
|
* [IMST iC880A-SPI](http://webshop.imst.de/ic880a-spi-lorawan-concentrator-868mhz.html). Preferable configured as described [by TTN-ZH](https://github.com/ttn-zh/ic880a-gateway/wiki). You **do not** need to follow the **Setting up the software** step, as the setup scripts in this repository does it for you.
|
||||||
* [LinkLabs Raspberry Pi "Hat"](http://link-labs.myshopify.com/products/lorawan-raspberry-pi-board)
|
* [LinkLabs Raspberry Pi "Hat"](http://link-labs.myshopify.com/products/lorawan-raspberry-pi-board)
|
||||||
* [RisingHF IoT Dicovery](http://www.risinghf.com/product/risinghf-iot-dicovery/?lang=en)
|
* [RisingHF IoT Dicovery](http://www.risinghf.com/product/risinghf-iot-dicovery/?lang=en)
|
||||||
* [RAK831](http://www.rakwireless.com/en/WisKeyOSH/RAK831)
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@ -40,10 +37,12 @@ For a more complete list of possible environment variables, see [CONFIGURATION](
|
|||||||
|
|
||||||
### Device environment variables - no GPS
|
### Device environment variables - no GPS
|
||||||
|
|
||||||
For example, for an IMST iC880A or RAK831 with no GPS, the MINIMUM environment variables that you should configure at this screen should look something like this:
|
For example, for an IMST iC880A with no GPS, the MINIMUM environment variables that you should configure at this screen should look something like this:
|
||||||
|
|
||||||
Name | Value
|
Name | Value
|
||||||
------------------|--------------------------
|
------------------|--------------------------
|
||||||
|
GW_TYPE | imst-ic880a-spi
|
||||||
|
GW_CONTACT_EMAIL | yourname@yourdomain.com
|
||||||
GW_ID | The gateway ID from the TTN console
|
GW_ID | The gateway ID from the TTN console
|
||||||
GW_KEY | The gateway KEY from the TTN console
|
GW_KEY | The gateway KEY from the TTN console
|
||||||
GW_RESET_PIN | 22 (optional)
|
GW_RESET_PIN | 22 (optional)
|
||||||
@ -56,7 +55,8 @@ GW_RESET_PIN can be left out if you are using Gonzalo Casas' backplane board, or
|
|||||||
For example a LinkLabs gateway, which has a built-in GPS, you need:
|
For example a LinkLabs gateway, which has a built-in GPS, you need:
|
||||||
|
|
||||||
Name | Value
|
Name | Value
|
||||||
------------------|--------------------------
|
------------------|--------------------------
|
||||||
|
GW_CONTACT_EMAIL | yourname@yourdomain.com
|
||||||
GW_ID | The gateway ID from the TTN console
|
GW_ID | The gateway ID from the TTN console
|
||||||
GW_KEY | The gateway KEY from the TTN console
|
GW_KEY | The gateway KEY from the TTN console
|
||||||
GW_GPS | true
|
GW_GPS | true
|
||||||
@ -76,16 +76,14 @@ ch2i<br />https://github.com/ch2i/iC880A-Raspberry-PI | 11
|
|||||||
Linklabs Rasberry Pi Hat<br />https://www.amazon.co.uk/868-MHz-LoRaWAN-RPi-Shield/dp/B01G7G54O2 | 29 (untested)
|
Linklabs Rasberry Pi Hat<br />https://www.amazon.co.uk/868-MHz-LoRaWAN-RPi-Shield/dp/B01G7G54O2 | 29 (untested)
|
||||||
Rising HF Board<br />http://www.risinghf.com/product/risinghf-iot-dicovery/?lang=en | 26
|
Rising HF Board<br />http://www.risinghf.com/product/risinghf-iot-dicovery/?lang=en | 26
|
||||||
IMST backplane or Lite gateway<br />https://wireless-solutions.de/products/long-range-radio/lora_lite_gateway.html | 29 (untested)
|
IMST backplane or Lite gateway<br />https://wireless-solutions.de/products/long-range-radio/lora_lite_gateway.html | 29 (untested)
|
||||||
Coredump backplane<br />https://github.com/dbrgn/ic880a-backplane/<br />https://shop.coredump.ch/product/ic880a-lorawan-gateway-backplane/ | 22
|
|
||||||
RAK backplane<br /> | 11
|
|
||||||
|
|
||||||
|
|
||||||
If you get the message
|
If you get the message
|
||||||
`ERROR: [main] failed to start the concentrator`
|
`ERROR: [main] failed to start the concentrator`
|
||||||
after resin.io is finished downloading the application, or when restarting the gateway, it most likely means the `GW_RESET_PIN` you defined is incorrect. Alternatively the problem can be caused by the hardware, typically for the `IMST iC880A-SPI` board with insufficient voltage, try another power supply or slightly increase the voltage.
|
after resin.io is finished downloading the application, or when restarting the gateway, it most likely means the `GW_RESET_PIN` you defined is incorrect.
|
||||||
|
|
||||||
|
|
||||||
## Special note for using a Raspberry Pi 3
|
## Special note for using the LinkLabs gateway on a Raspberry Pi 3
|
||||||
|
|
||||||
There is a backward incomatibility between the Raspberry Pi 1 and 2 hardware, and Raspberry Pi 3. For Raspberry Pi 3, it is necessary to make a small additional configuration change.
|
There is a backward incomatibility between the Raspberry Pi 1 and 2 hardware, and Raspberry Pi 3. For Raspberry Pi 3, it is necessary to make a small additional configuration change.
|
||||||
|
|
||||||
@ -95,10 +93,9 @@ Add a New config variable as follows:
|
|||||||
|
|
||||||
### Application config variables
|
### Application config variables
|
||||||
|
|
||||||
Name | Value
|
Name | Value
|
||||||
------------------------------|--------------------------
|
------------------------------|--------------------------
|
||||||
RESIN_HOST_CONFIG_core_freq | 250
|
RESIN_HOST_CONFIG_core_freq | 250
|
||||||
RESIN_HOST_CONFIG_dtoverlay | pi3-miniuart-bt
|
|
||||||
|
|
||||||
## TRANSFERRING TTN GATEWAY SOFTWARE TO RESIN SO THAT IT MAY BE DOWNLOADED ON YOUR DEVICES
|
## TRANSFERRING TTN GATEWAY SOFTWARE TO RESIN SO THAT IT MAY BE DOWNLOADED ON YOUR DEVICES
|
||||||
|
|
||||||
@ -157,18 +154,11 @@ If you get the error below please check if your ssh public key has been added to
|
|||||||
```
|
```
|
||||||
git add .
|
git add .
|
||||||
git commit -m "Updated gateway version"
|
git commit -m "Updated gateway version"
|
||||||
git push -f resin master
|
git push -f resin master"
|
||||||
```
|
```
|
||||||
|
|
||||||
- For devices without a GPS, the location that is configured on the TTN console is used. This location is only read at startup of the gateway. Therefore, after you set or changed the location, restart the application from the resin.io console.
|
- For devices without a GPS, the location that is configured on the TTN console is used. This location is only read at startup of the gateway. Therefore, after you set or changed the location, restart the application from the resin.io console.
|
||||||
|
|
||||||
# Device statistics
|
|
||||||
If you want to show nice looking statistics for your gateway(s) there are a couple of additional steps to take. First, copy `Dockerfile.template.metering` to `Dockerfile.template`. Next copy `start.sh.metering` to `start.sh`. Now use the instructions above to update the resin image.
|
|
||||||
|
|
||||||
Once the new image is deployed, go to the resin.io dashboard for your devices and select 'Enable Public device URL' in the drop down menu (the one to the right of the light bulb). That is all that is required to provide metrics. Now you will need to install a metrics collector on a seperate system as outlined in [Fleet-wide Machine Metrics Monitoring in 20mins](https://resin.io/blog/prometheusv2/).
|
|
||||||
|
|
||||||
(To show packet forwarder graphs you need to add your own graphs to the provided templates)
|
|
||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
|
|
||||||
* [Gonzalo Casas](https://github.com/gonzalocasas) on the [iC880a-based gateway](https://github.com/ttn-zh/ic880a-gateway/tree/spi)
|
* [Gonzalo Casas](https://github.com/gonzalocasas) on the [iC880a-based gateway](https://github.com/ttn-zh/ic880a-gateway/tree/spi)
|
||||||
|
20
dev/build.sh
20
dev/build.sh
@ -5,6 +5,17 @@ INSTALL_DIR="/opt/ttn-gateway"
|
|||||||
mkdir -p $INSTALL_DIR/dev
|
mkdir -p $INSTALL_DIR/dev
|
||||||
cd $INSTALL_DIR/dev
|
cd $INSTALL_DIR/dev
|
||||||
|
|
||||||
|
if [ ! -d wiringPi ]; then
|
||||||
|
git clone git://git.drogon.net/wiringPi || { echo 'Cloning wiringPi failed.' ; exit 1; }
|
||||||
|
cd wiringPi
|
||||||
|
else
|
||||||
|
cd wiringPi
|
||||||
|
git reset --hard
|
||||||
|
git pull
|
||||||
|
fi
|
||||||
|
./build
|
||||||
|
cd ..
|
||||||
|
|
||||||
if [ ! -d lora_gateway ]; then
|
if [ ! -d lora_gateway ]; then
|
||||||
git clone https://github.com/kersing/lora_gateway.git || { echo 'Cloning lora_gateway failed.' ; exit 1; }
|
git clone https://github.com/kersing/lora_gateway.git || { echo 'Cloning lora_gateway failed.' ; exit 1; }
|
||||||
else
|
else
|
||||||
@ -59,10 +70,13 @@ else
|
|||||||
cd ..
|
cd ..
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
apt-get -y install protobuf-compiler libprotobuf-dev libprotoc-dev automake libtool autoconf python-dev python-rpi.gpio
|
||||||
|
|
||||||
cd $INSTALL_DIR/dev/lora_gateway/libloragw
|
cd $INSTALL_DIR/dev/lora_gateway/libloragw
|
||||||
sed -i -e 's/PLATFORM= .*$/PLATFORM= imst_rpi/g' library.cfg
|
sed -i -e 's/PLATFORM= .*$/PLATFORM= imst_rpi/g' library.cfg
|
||||||
sed -i -e 's/CFG_SPI= .*$/CFG_SPI= native/g' library.cfg
|
sed -i -e 's/CFG_SPI= .*$/CFG_SPI= native/g' library.cfg
|
||||||
make -j$(nproc)
|
make
|
||||||
|
|
||||||
cd $INSTALL_DIR/dev/protobuf-c
|
cd $INSTALL_DIR/dev/protobuf-c
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
@ -78,11 +92,11 @@ make install
|
|||||||
|
|
||||||
cd $INSTALL_DIR/dev/ttn-gateway-connector
|
cd $INSTALL_DIR/dev/ttn-gateway-connector
|
||||||
cp config.mk.in config.mk
|
cp config.mk.in config.mk
|
||||||
make -j$(nproc)
|
make
|
||||||
cp bin/libttn-gateway-connector.so /usr/lib/
|
cp bin/libttn-gateway-connector.so /usr/lib/
|
||||||
|
|
||||||
cd $INSTALL_DIR/dev/packet_forwarder/mp_pkt_fwd/
|
cd $INSTALL_DIR/dev/packet_forwarder/mp_pkt_fwd/
|
||||||
make -j$(nproc)
|
make
|
||||||
|
|
||||||
# Copy things needed at runtime to where they'll be expected
|
# Copy things needed at runtime to where they'll be expected
|
||||||
cp $INSTALL_DIR/dev/packet_forwarder/mp_pkt_fwd/mp_pkt_fwd $INSTALL_DIR/mp_pkt_fwd
|
cp $INSTALL_DIR/dev/packet_forwarder/mp_pkt_fwd/mp_pkt_fwd $INSTALL_DIR/mp_pkt_fwd
|
||||||
|
BIN
gwexporter.tgz
BIN
gwexporter.tgz
Binary file not shown.
125
run.py
125
run.py
@ -7,6 +7,7 @@ Based on: https://github.com/rayozzie/ttn-resin-gateway-rpi/blob/master/run.sh
|
|||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
|
import stat
|
||||||
import urllib2
|
import urllib2
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
@ -23,7 +24,7 @@ except RuntimeError:
|
|||||||
|
|
||||||
GWID_PREFIX="FFFE"
|
GWID_PREFIX="FFFE"
|
||||||
|
|
||||||
if not os.path.exists("/opt/ttn-gateway/mp_pkt_fwd"):
|
if not os.path.exists("mp_pkt_fwd"):
|
||||||
print ("ERROR: gateway executable not found. Is it built yet?")
|
print ("ERROR: gateway executable not found. Is it built yet?")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
@ -49,14 +50,31 @@ print ("*******************")
|
|||||||
print ("*** Configuration:")
|
print ("*** Configuration:")
|
||||||
print ("*******************")
|
print ("*******************")
|
||||||
|
|
||||||
if os.environ.get("GW_EUI")==None:
|
if os.environ.get("GW_ID")==None:
|
||||||
# The FFFE should be inserted in the middle (so xxxxxxFFFExxxxxx)
|
print ("ERROR: GW_ID required")
|
||||||
my_eui = format(uuid.getnode(), '012x')
|
print ("See https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector")
|
||||||
my_eui = my_eui[:6]+GWID_PREFIX+my_eui[6:]
|
sys.exit(0)
|
||||||
my_eui = my_eui.upper()
|
|
||||||
else:
|
|
||||||
my_eui = os.environ.get("GW_EUI")
|
|
||||||
|
|
||||||
|
if os.environ.get("GW_KEY")==None:
|
||||||
|
print ("ERROR: GW_KEY required")
|
||||||
|
print ("See https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# The FFFE should be inserted in the middle (so xxxxxxFFFExxxxxx)
|
||||||
|
my_eui = format(uuid.getnode(), '012x')
|
||||||
|
my_eui = my_eui[:6]+GWID_PREFIX+my_eui[6:]
|
||||||
|
my_eui = my_eui.upper()
|
||||||
|
|
||||||
|
print ("Gateway ID:\t"+os.environ.get("GW_ID"))
|
||||||
|
print ("Gateway EUI:\t"+my_eui)
|
||||||
|
print ("Gateway Key:\t"+os.environ.get("GW_KEY"))
|
||||||
|
print ("Has hardware GPS:\t"+str(os.getenv('GW_GPS', False)))
|
||||||
|
print ("Hardware GPS port:\t"+os.getenv('GW_GPS_PORT', "/dev/ttyAMA0"))
|
||||||
|
|
||||||
|
|
||||||
|
print ("*******************")
|
||||||
|
print ("*** Fetching config from TTN account server")
|
||||||
|
print ("*******************")
|
||||||
|
|
||||||
# Define default configs
|
# Define default configs
|
||||||
description = os.getenv('GW_DESCRIPTION', "")
|
description = os.getenv('GW_DESCRIPTION', "")
|
||||||
@ -64,25 +82,10 @@ placement = ""
|
|||||||
latitude = os.getenv('GW_REF_LATITUDE', 0)
|
latitude = os.getenv('GW_REF_LATITUDE', 0)
|
||||||
longitude = os.getenv('GW_REF_LONGITUDE', 0)
|
longitude = os.getenv('GW_REF_LONGITUDE', 0)
|
||||||
altitude = os.getenv('GW_REF_ALTITUDE', 0)
|
altitude = os.getenv('GW_REF_ALTITUDE', 0)
|
||||||
frequency_plan_url = os.getenv('FREQ_PLAN_URL', "https://account.thethingsnetwork.org/api/v2/frequency-plans/EU_863_870")
|
frequency_plan_url = "https://account.thethingsnetwork.org/api/v2/frequency-plans/EU_863_870"
|
||||||
|
|
||||||
# Fetch config from TTN if TTN is enabled
|
# Fetch config from TTN if TTN is enabled
|
||||||
if(os.getenv('SERVER_TTN', "true")=="true"):
|
if(os.getenv('SERVER_TTN', True)):
|
||||||
|
|
||||||
if os.environ.get("GW_ID")==None:
|
|
||||||
print ("ERROR: GW_ID required")
|
|
||||||
print ("See https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if os.environ.get("GW_KEY")==None:
|
|
||||||
print ("ERROR: GW_KEY required")
|
|
||||||
print ("See https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
print ("*******************")
|
|
||||||
print ("*** Fetching config from TTN account server")
|
|
||||||
print ("*******************")
|
|
||||||
|
|
||||||
# Fetch the URL, if it fails try 30 seconds later again.
|
# Fetch the URL, if it fails try 30 seconds later again.
|
||||||
config_response = ""
|
config_response = ""
|
||||||
try:
|
try:
|
||||||
@ -128,28 +131,19 @@ if(os.getenv('SERVER_TTN', "true")=="true"):
|
|||||||
fallback_routers.append(fb_router["mqtt_address"])
|
fallback_routers.append(fb_router["mqtt_address"])
|
||||||
|
|
||||||
|
|
||||||
print ("Gateway ID:\t"+os.environ.get("GW_ID"))
|
print ("Router:\t\t\t"+router)
|
||||||
print ("Gateway Key:\t"+os.environ.get("GW_KEY"))
|
|
||||||
print ("Frequency plan:\t\t"+frequency_plan)
|
print ("Frequency plan:\t\t"+frequency_plan)
|
||||||
print ("Frequency plan url:\t"+frequency_plan_url)
|
print ("Frequency plan url:\t"+frequency_plan_url)
|
||||||
print ("Gateway description:\t"+description)
|
print ("Gateway description:\t"+description)
|
||||||
print ("Gateway placement:\t"+placement)
|
print ("Gateway placement:\t"+placement)
|
||||||
print ("Router:\t\t\t"+router)
|
print ("Latitude:\t\t"+str(latitude))
|
||||||
|
print ("Longitude:\t\t"+str(longitude))
|
||||||
|
print ("Altitude:\t\t"+str(altitude))
|
||||||
print ("")
|
print ("")
|
||||||
print ("Fallback routers:")
|
print ("Fallback routers:")
|
||||||
for fb_router in fallback_routers:
|
for fb_router in fallback_routers:
|
||||||
print ("\t"+fb_router)
|
print ("\t"+fb_router)
|
||||||
# Done fetching config from TTN
|
# Done fetching config from TTN
|
||||||
else:
|
|
||||||
print ("TTN gateway connector disabled. Not fetching config from account server.")
|
|
||||||
|
|
||||||
print ("Latitude:\t\t"+str(latitude))
|
|
||||||
print ("Longitude:\t\t"+str(longitude))
|
|
||||||
print ("Altitude:\t\t"+str(altitude))
|
|
||||||
print ("Gateway EUI:\t"+my_eui)
|
|
||||||
print ("Has hardware GPS:\t"+str(os.getenv('GW_GPS', False)))
|
|
||||||
print ("Hardware GPS port:\t"+os.getenv('GW_GPS_PORT', "/dev/ttyAMA0"))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Retrieve global_conf
|
# Retrieve global_conf
|
||||||
@ -172,23 +166,18 @@ gateway_conf = {}
|
|||||||
gateway_conf['gateway_ID'] = my_eui
|
gateway_conf['gateway_ID'] = my_eui
|
||||||
gateway_conf['contact_email'] = os.getenv('GW_CONTACT_EMAIL', "")
|
gateway_conf['contact_email'] = os.getenv('GW_CONTACT_EMAIL', "")
|
||||||
gateway_conf['description'] = description
|
gateway_conf['description'] = description
|
||||||
gateway_conf['stat_file'] = 'loragwstat.json'
|
|
||||||
|
|
||||||
if(os.getenv('GW_LOGGER', "false")=="true"):
|
if(os.getenv('GW_FWD_CRC_ERR', False)=="true"):
|
||||||
gateway_conf['logger'] = True
|
|
||||||
else:
|
|
||||||
gateway_conf['logger'] = False
|
|
||||||
|
|
||||||
if(os.getenv('GW_FWD_CRC_ERR', "false")=="true"):
|
|
||||||
#default is False
|
#default is False
|
||||||
gateway_conf['forward_crc_error'] = True
|
gateway_conf['forward_crc_error'] = True
|
||||||
|
|
||||||
if(os.getenv('GW_FWD_CRC_VAL', "true")=="false"):
|
if(os.getenv('GW_FWD_CRC_VAL', True)=="false"):
|
||||||
#default is True
|
#default is True
|
||||||
gateway_conf['forward_crc_valid'] = False
|
gateway_conf['forward_crc_valid'] = False
|
||||||
|
|
||||||
# Parse GW_GPS env var. It is a string, we need a boolean.
|
# Parse GW_GPS env var. It is a string, we need a boolean.
|
||||||
if(os.getenv('GW_GPS', "false")=="true"):
|
gw_gps = os.getenv('GW_GPS', False)
|
||||||
|
if(gw_gps=="true"):
|
||||||
gw_gps = True
|
gw_gps = True
|
||||||
else:
|
else:
|
||||||
gw_gps = False
|
gw_gps = False
|
||||||
@ -218,7 +207,7 @@ else:
|
|||||||
gateway_conf['servers'] = []
|
gateway_conf['servers'] = []
|
||||||
|
|
||||||
# Add TTN server
|
# Add TTN server
|
||||||
if(os.getenv('SERVER_TTN', "true")=="true"):
|
if(os.getenv('SERVER_TTN', True)!="false"):
|
||||||
server = {}
|
server = {}
|
||||||
server['serv_type'] = "ttn"
|
server['serv_type'] = "ttn"
|
||||||
server['server_address'] = router
|
server['server_address'] = router
|
||||||
@ -227,22 +216,6 @@ if(os.getenv('SERVER_TTN', "true")=="true"):
|
|||||||
server['serv_gw_key'] = os.environ.get("GW_KEY")
|
server['serv_gw_key'] = os.environ.get("GW_KEY")
|
||||||
server['serv_enabled'] = True
|
server['serv_enabled'] = True
|
||||||
gateway_conf['servers'].append(server)
|
gateway_conf['servers'].append(server)
|
||||||
else:
|
|
||||||
if(os.getenv('SERVER_0_ENABLED', "false")=="true"):
|
|
||||||
server = {}
|
|
||||||
if(os.getenv('SERVER_0_TYPE', "semtech")=="ttn"):
|
|
||||||
server['serv_type'] = "ttn"
|
|
||||||
server['serv_gw_id'] = os.environ.get("SERVER_0_GWID")
|
|
||||||
server['serv_gw_key'] = os.environ.get("SERVER_0_GWKEY")
|
|
||||||
server['server_address'] = os.environ.get("SERVER_0_ADDRESS")
|
|
||||||
server['serv_port_up'] = int(os.getenv("SERVER_0_PORTUP", 1700))
|
|
||||||
server['serv_port_down'] = int(os.getenv("SERVER_0_PORTDOWN", 1700))
|
|
||||||
server['serv_enabled'] = True
|
|
||||||
if(os.getenv('SERVER_0_DOWNLINK', "false")=="true"):
|
|
||||||
server['serv_down_enabled'] = True
|
|
||||||
else:
|
|
||||||
server['serv_down_enabled'] = False
|
|
||||||
gateway_conf['servers'].append(server)
|
|
||||||
|
|
||||||
# Add up to 3 additional servers
|
# Add up to 3 additional servers
|
||||||
if(os.getenv('SERVER_1_ENABLED', "false")=="true"):
|
if(os.getenv('SERVER_1_ENABLED', "false")=="true"):
|
||||||
@ -261,7 +234,7 @@ if(os.getenv('SERVER_1_ENABLED', "false")=="true"):
|
|||||||
server['serv_down_enabled'] = False
|
server['serv_down_enabled'] = False
|
||||||
gateway_conf['servers'].append(server)
|
gateway_conf['servers'].append(server)
|
||||||
|
|
||||||
if(os.getenv('SERVER_2_ENABLED', "false")=="true"):
|
if(os.getenv('SERVER_2_ENABLED', False)):
|
||||||
server = {}
|
server = {}
|
||||||
if(os.getenv('SERVER_2_TYPE', "semtech")=="ttn"):
|
if(os.getenv('SERVER_2_TYPE', "semtech")=="ttn"):
|
||||||
server['serv_type'] = "ttn"
|
server['serv_type'] = "ttn"
|
||||||
@ -277,7 +250,7 @@ if(os.getenv('SERVER_2_ENABLED', "false")=="true"):
|
|||||||
server['serv_down_enabled'] = False
|
server['serv_down_enabled'] = False
|
||||||
gateway_conf['servers'].append(server)
|
gateway_conf['servers'].append(server)
|
||||||
|
|
||||||
if(os.getenv('SERVER_3_ENABLED', "false")=="true"):
|
if(os.getenv('SERVER_3_ENABLED', False)):
|
||||||
server = {}
|
server = {}
|
||||||
if(os.getenv('SERVER_3_TYPE', "semtech")=="ttn"):
|
if(os.getenv('SERVER_3_TYPE', "semtech")=="ttn"):
|
||||||
server['serv_type'] = "ttn"
|
server['serv_type'] = "ttn"
|
||||||
@ -297,10 +270,26 @@ if(os.getenv('SERVER_3_ENABLED', "false")=="true"):
|
|||||||
# We merge the json objects from the global_conf and local_conf and save it to the global_conf.
|
# We merge the json objects from the global_conf and local_conf and save it to the global_conf.
|
||||||
# Therefore there will not be a local_conf.json file.
|
# Therefore there will not be a local_conf.json file.
|
||||||
local_conf = {'SX1301_conf': sx1301_conf, 'gateway_conf': gateway_conf}
|
local_conf = {'SX1301_conf': sx1301_conf, 'gateway_conf': gateway_conf}
|
||||||
with open('/opt/ttn-gateway/global_conf.json', 'w') as the_file:
|
with open('global_conf.json', 'w') as the_file:
|
||||||
the_file.write(json.dumps(local_conf, indent=4))
|
the_file.write(json.dumps(local_conf, indent=4))
|
||||||
|
|
||||||
|
|
||||||
|
# Cayenne monitoring script
|
||||||
|
"""
|
||||||
|
wget https://cayenne.mydevices.com/dl/rpi_lv7d88b029.sh
|
||||||
|
sudo bash rpi_lv7d88b029.sh -v
|
||||||
|
"""
|
||||||
|
if(os.environ.get("CAYENNE_SCRIPT")!=None):
|
||||||
|
try:
|
||||||
|
response = urllib2.urlopen(os.environ.get("CAYENNE_SCRIPT"), timeout=30)
|
||||||
|
cayenne_script = response.read()
|
||||||
|
with open('rpi_cayenne.sh', 'w') as the_file:
|
||||||
|
the_file.write(cayenne_script)
|
||||||
|
os.chmod('rpi_cayenne.sh', stat.S_IEXEC)
|
||||||
|
subprocess.call(["./rpi_cayenne.sh"])
|
||||||
|
except urllib2.URLError as err:
|
||||||
|
print ("Unable to fetch Cayenne script")
|
||||||
|
|
||||||
|
|
||||||
# Endless loop to reset and restart packet forwarder
|
# Endless loop to reset and restart packet forwarder
|
||||||
while True:
|
while True:
|
||||||
@ -336,5 +325,5 @@ while True:
|
|||||||
GPIO.cleanup(22)
|
GPIO.cleanup(22)
|
||||||
|
|
||||||
# Start forwarder
|
# Start forwarder
|
||||||
subprocess.call("/opt/ttn-gateway/mp_pkt_fwd -c /opt/ttn-gateway", shell=True)
|
subprocess.call(["./mp_pkt_fwd"])
|
||||||
time.sleep(15)
|
time.sleep(15)
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Start the node exporter
|
|
||||||
mkdir /mnt/ramdisk
|
|
||||||
mount -t tmpfs -o size=8m tmpfs /mnt/ramdisk
|
|
||||||
cd /mnt/ramdisk
|
|
||||||
/opt/ttn-gateway/run.py &
|
|
||||||
|
|
||||||
# WORKAROUND: Add symlink, as gwexporter otherwise currently don't seem to find this file
|
|
||||||
ln -s /mnt/ramdisk/loragwstat.json /opt/gwexporter/loragwstat.json
|
|
||||||
|
|
||||||
export PATH=$PATH:/opt/gwexporter/bin
|
|
||||||
node /opt/gwexporter/gwexporter.js &
|
|
||||||
|
|
||||||
cd /etc && ./node_exporter -web.listen-address ":81"
|
|
Loading…
Reference in New Issue
Block a user