Compare commits

..

1 Commits

Author SHA1 Message Date
jpmeijers
094756c414 Download and run cayenne script in foreground 2017-06-13 19:32:42 +02:00
9 changed files with 119 additions and 241 deletions

View File

@ -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

View File

@ -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"]

View File

@ -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"]

View File

@ -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)

View File

@ -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

Binary file not shown.

125
run.py
View File

@ -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)

View File

@ -1,3 +0,0 @@
#!/bin/bash
python /opt/ttn-gateway/run.py

View File

@ -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"