Compare commits

...

19 Commits

Author SHA1 Message Date
JP Meijers
2b4bc99148
Update CONFIGURATION.md
Document logger variable
2018-02-28 10:55:31 +02:00
JP Meijers
992d6b6ce6 Enable logger with env var 2018-02-28 10:47:01 +02:00
JP Meijers
43f611a3d2
Update README.md 2018-02-18 22:06:56 +02:00
JP Meijers
19e5614359
Update README.md
Remove unnecessary variables for minimal configuration
2018-02-14 22:51:03 +02:00
JP Meijers
130c6b7173
Update README.md
Few formatting fixes in readme.
2018-02-13 10:10:35 +02:00
JP Meijers
ddca246e87
Merge pull request #9 from The-Box-Development/master
Improvements made for the TTN Conference gateway workshop
2018-02-13 10:07:06 +02:00
Jac Kersing
2922f63a85 Two stage build to reduce image size and build improvements provided by @imrehg.
Add (optional) metering support for use with Prometheus.
2018-02-12 18:32:11 +01:00
jpmeijers
e40d71b4a8 Add the ability to manually configure server 0, which is normally used by TTN 2017-11-12 22:52:13 +02:00
jpmeijers
788cdf9d35 Add variable for RPi3 with hardware gps 2017-11-12 21:58:02 +02:00
jpmeijers
6893467ce9 Do not require ID and Key when using legacy 2017-11-12 21:52:08 +02:00
jpmeijers
22be0b21c0 Document new variable 2017-11-12 21:51:47 +02:00
jpmeijers
8437d03864 Disabling TTN didn't work. 2017-11-12 21:29:05 +02:00
JP Meijers
7cca889cb4
Update CONFIGURATION.md 2017-11-09 10:22:50 +02:00
JP Meijers
d68c4b2904
Update run.py
Add ability to override the EUI.
Fix a bug where server 2 and server 3 are never used.
2017-11-09 10:12:03 +02:00
JP Meijers
16a374665d
Update CONFIGURATION.md
Fix markdown header formatting
2017-11-08 10:21:34 +02:00
JP Meijers
b8aca75079 Merge pull request #4 from dbrgn/patch-1
Add Coredump backplane to list of reset pins
2017-09-01 11:21:59 +02:00
Danilo Bargen
74bc69640a Add Coredump backplane to list of reset pins
It uses the same reset pin as the Gonzalo Casas backplane. See https://github.com/dbrgn/ic880a-backplane/blob/master/schematics-v1.2.pdf for verification.
2017-09-01 09:53:18 +02:00
JP Meijers
845e607300 Merge pull request #3 from SloMusti/troubleshooting
Updated the readme with details about the error
2017-08-03 18:50:25 +02:00
SloMusti
9b193444b8 Updated the readme with details about the error 2017-07-31 18:09:36 +02:00
9 changed files with 241 additions and 102 deletions

View File

@ -1,38 +1,44 @@
#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_CONTACT_EMAIL optional - default an empty string * GW_EUI - by default an EUI will be generated from the Raspberry Pi's ethernet MAC address.
The gateway owner's contact information. Will be overridden by the value from the TTN console. * 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.
* 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`
* 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.
##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
@ -64,11 +70,35 @@ 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,18 +1,29 @@
FROM resin/%%RESIN_MACHINE_NAME%%-buildpack-deps FROM resin/%%RESIN_MACHINE_NAME%%-debian:latest AS buildstep
# 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/
# Build the gateway (or comment this out if debugging on-device) # downloading utils
RUN ./dev/build.sh && rm -rf ./dev 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
# Start it up COPY dev dev
CMD ["sh", "-c", "./run.py"] RUN ./dev/build.sh
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

@ -0,0 +1,58 @@
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,6 +1,8 @@
# 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.
@ -14,6 +16,7 @@ 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
@ -37,12 +40,10 @@ 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 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 or RAK831 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)
@ -55,8 +56,7 @@ 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,14 +76,16 @@ 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. 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.
## Special note for using the LinkLabs gateway on a Raspberry Pi 3 ## Special note for using 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.
@ -93,9 +95,10 @@ 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
@ -154,11 +157,18 @@ 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,17 +5,6 @@ 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
@ -70,13 +59,10 @@ 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 make -j$(nproc)
cd $INSTALL_DIR/dev/protobuf-c cd $INSTALL_DIR/dev/protobuf-c
./autogen.sh ./autogen.sh
@ -92,11 +78,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 make -j$(nproc)
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 make -j$(nproc)
# 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 Normal file

Binary file not shown.

110
run.py
View File

@ -23,7 +23,7 @@ except RuntimeError:
GWID_PREFIX="FFFE" GWID_PREFIX="FFFE"
if not os.path.exists("mp_pkt_fwd"): if not os.path.exists("/opt/ttn-gateway/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,31 +49,14 @@ print ("*******************")
print ("*** Configuration:") print ("*** Configuration:")
print ("*******************") print ("*******************")
if os.environ.get("GW_ID")==None: if os.environ.get("GW_EUI")==None:
print ("ERROR: GW_ID required") # The FFFE should be inserted in the middle (so xxxxxxFFFExxxxxx)
print ("See https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector") my_eui = format(uuid.getnode(), '012x')
sys.exit(0) my_eui = my_eui[:6]+GWID_PREFIX+my_eui[6:]
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', "")
@ -81,10 +64,25 @@ 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 = "https://account.thethingsnetwork.org/api/v2/frequency-plans/EU_863_870" frequency_plan_url = os.getenv('FREQ_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)): if(os.getenv('SERVER_TTN', "true")=="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:
@ -130,19 +128,28 @@ if(os.getenv('SERVER_TTN', True)):
fallback_routers.append(fb_router["mqtt_address"]) fallback_routers.append(fb_router["mqtt_address"])
print ("Router:\t\t\t"+router) print ("Gateway ID:\t"+os.environ.get("GW_ID"))
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 ("Latitude:\t\t"+str(latitude)) print ("Router:\t\t\t"+router)
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
@ -165,18 +172,23 @@ 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_FWD_CRC_ERR', False)=="true"): if(os.getenv('GW_LOGGER', "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.
gw_gps = os.getenv('GW_GPS', False) if(os.getenv('GW_GPS', "false")=="true"):
if(gw_gps=="true"):
gw_gps = True gw_gps = True
else: else:
gw_gps = False gw_gps = False
@ -206,7 +218,7 @@ else:
gateway_conf['servers'] = [] gateway_conf['servers'] = []
# Add TTN server # Add TTN server
if(os.getenv('SERVER_TTN', True)!="false"): if(os.getenv('SERVER_TTN', "true")=="true"):
server = {} server = {}
server['serv_type'] = "ttn" server['serv_type'] = "ttn"
server['server_address'] = router server['server_address'] = router
@ -215,6 +227,22 @@ if(os.getenv('SERVER_TTN', True)!="false"):
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"):
@ -233,7 +261,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)): if(os.getenv('SERVER_2_ENABLED', "false")=="true"):
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"
@ -249,7 +277,7 @@ if(os.getenv('SERVER_2_ENABLED', False)):
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)): if(os.getenv('SERVER_3_ENABLED', "false")=="true"):
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"
@ -269,12 +297,10 @@ if(os.getenv('SERVER_3_ENABLED', False)):
# 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('global_conf.json', 'w') as the_file: with open('/opt/ttn-gateway/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))
# TODO: Cayenne monitoring script
# Endless loop to reset and restart packet forwarder # Endless loop to reset and restart packet forwarder
while True: while True:
@ -310,5 +336,5 @@ while True:
GPIO.cleanup(22) GPIO.cleanup(22)
# Start forwarder # Start forwarder
subprocess.call(["./mp_pkt_fwd"]) subprocess.call("/opt/ttn-gateway/mp_pkt_fwd -c /opt/ttn-gateway", shell=True)
time.sleep(15) time.sleep(15)

3
start.sh Normal file
View File

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

15
start.sh.metering Normal file
View File

@ -0,0 +1,15 @@
#!/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"