Compare commits
19 Commits
feature/ca
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
2b4bc99148 | ||
|
992d6b6ce6 | ||
|
43f611a3d2 | ||
|
19e5614359 | ||
|
130c6b7173 | ||
|
ddca246e87 | ||
|
2922f63a85 | ||
|
e40d71b4a8 | ||
|
788cdf9d35 | ||
|
6893467ce9 | ||
|
22be0b21c0 | ||
|
8437d03864 | ||
|
7cca889cb4 | ||
|
d68c4b2904 | ||
|
16a374665d | ||
|
b8aca75079 | ||
|
74bc69640a | ||
|
845e607300 | ||
|
9b193444b8 |
@ -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
|
||||||
|
|
||||||
|
@ -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"]
|
||||||
|
58
Dockerfile.template.metering
Normal file
58
Dockerfile.template.metering
Normal 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"]
|
24
README.md
24
README.md
@ -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)
|
||||||
@ -56,7 +57,6 @@ 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.
|
||||||
|
|
||||||
@ -96,6 +98,7 @@ Add a New config variable as follows:
|
|||||||
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)
|
||||||
|
20
dev/build.sh
20
dev/build.sh
@ -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
BIN
gwexporter.tgz
Normal file
Binary file not shown.
110
run.py
110
run.py
@ -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)
|
||||||
|
15
start.sh.metering
Normal file
15
start.sh.metering
Normal 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"
|
Loading…
Reference in New Issue
Block a user