diff --git a/Dockerfile.template b/Dockerfile.template index 4c149bc..4e0eb42 100644 --- a/Dockerfile.template +++ b/Dockerfile.template @@ -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/ -# Build the gateway (or comment this out if debugging on-device) -RUN ./dev/build.sh && rm -rf ./dev +# 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 -# Start it up -CMD ["sh", "-c", "./run.py"] +COPY dev dev +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"] diff --git a/Dockerfile.template.metering b/Dockerfile.template.metering new file mode 100644 index 0000000..648567c --- /dev/null +++ b/Dockerfile.template.metering @@ -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"] diff --git a/README.md b/README.md index 8d88893..602a6b3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,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. * [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) +* [RAK831](http://www.rakwireless.com/en/WisKeyOSH/RAK831) ## Prerequisites @@ -37,7 +38,7 @@ For a more complete list of possible environment variables, see [CONFIGURATION]( ### 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 ------------------|-------------------------- @@ -47,7 +48,7 @@ GW_ID | The gateway ID from the TTN console GW_KEY | The gateway KEY from the TTN console GW_RESET_PIN | 22 (optional) -GW_RESET_PIN can be left out if you are using Gonzalo Casas' backplane board, or any other setup using pin 22 as reset pin. This is because pin 22 is the default reset pin used by this resin.io setup. +GW_RESET_PIN can be left out if you are using Gonzalo Casas' backplane board, the RAK backplane for the RAK831, or any other setup using pin 22 as reset pin. This is because pin 22 is the default reset pin used by this resin.io setup. ### Device environment variables - with GPS @@ -77,6 +78,7 @@ Linklabs Rasberry Pi Hat
https://www.amazon.co.uk/868-MHz-LoRaWAN-RPi-Shiel Rising HF Board
http://www.risinghf.com/product/risinghf-iot-dicovery/?lang=en | 26 IMST backplane or Lite gateway
https://wireless-solutions.de/products/long-range-radio/lora_lite_gateway.html | 29 (untested) Coredump backplane
https://github.com/dbrgn/ic880a-backplane/
https://shop.coredump.ch/product/ic880a-lorawan-gateway-backplane/ | 22 +RAK backplane
| 11 If you get the message @@ -84,7 +86,7 @@ If you get the message 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. @@ -156,11 +158,22 @@ If you get the error below please check if your ssh public key has been added to ``` git add . 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. +# 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 * [Gonzalo Casas](https://github.com/gonzalocasas) on the [iC880a-based gateway](https://github.com/ttn-zh/ic880a-gateway/tree/spi) diff --git a/dev/build.sh b/dev/build.sh index 527e0d6..d998e9d 100755 --- a/dev/build.sh +++ b/dev/build.sh @@ -5,17 +5,6 @@ INSTALL_DIR="/opt/ttn-gateway" mkdir -p $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 git clone https://github.com/kersing/lora_gateway.git || { echo 'Cloning lora_gateway failed.' ; exit 1; } else @@ -70,13 +59,10 @@ else cd .. 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 sed -i -e 's/PLATFORM= .*$/PLATFORM= imst_rpi/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 ./autogen.sh @@ -92,11 +78,11 @@ make install cd $INSTALL_DIR/dev/ttn-gateway-connector cp config.mk.in config.mk -make +make -j$(nproc) cp bin/libttn-gateway-connector.so /usr/lib/ cd $INSTALL_DIR/dev/packet_forwarder/mp_pkt_fwd/ -make +make -j$(nproc) # 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 diff --git a/gwexporter.tgz b/gwexporter.tgz new file mode 100644 index 0000000..8a54425 Binary files /dev/null and b/gwexporter.tgz differ diff --git a/run.py b/run.py index 18515e6..334a8f4 100755 --- a/run.py +++ b/run.py @@ -23,7 +23,7 @@ except RuntimeError: 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?") sys.exit(0) @@ -172,6 +172,7 @@ gateway_conf = {} gateway_conf['gateway_ID'] = my_eui gateway_conf['contact_email'] = os.getenv('GW_CONTACT_EMAIL', "") gateway_conf['description'] = description +gateway_conf['stat_file'] = 'loragwstat.json' if(os.getenv('GW_FWD_CRC_ERR', "false")=="true"): #default is False @@ -291,7 +292,7 @@ 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. # Therefore there will not be a local_conf.json file. 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)) @@ -332,5 +333,5 @@ while True: GPIO.cleanup(22) # Start forwarder - subprocess.call(["./mp_pkt_fwd"]) + subprocess.call("/opt/ttn-gateway/mp_pkt_fwd -c /opt/ttn-gateway", shell=True) time.sleep(15) diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..489f446 --- /dev/null +++ b/start.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +python /opt/ttn-gateway/run.py diff --git a/start.sh.metering b/start.sh.metering new file mode 100644 index 0000000..9e83447 --- /dev/null +++ b/start.sh.metering @@ -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"