diff --git a/1_Pi_Config.sh b/1_Pi_Config.sh index 64de36b..ea9f5cf 100755 --- a/1_Pi_Config.sh +++ b/1_Pi_Config.sh @@ -22,6 +22,22 @@ if [[ "$REPLY" =~ ^(no|n|N)$ ]]; then exit 0 fi +# These functions have been copied from excellent Adafruit Read only tutorial +# https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/read-only-fs.sh +# the one inspired by my original article http://hallard.me/raspberry-pi-read-only/ +# That's an excellent demonstration of collaboration and open source sharing +# +# Given a filename, a regex pattern to match and a replacement string: +# Replace string if found, else no change. +# (# $1 = filename, $2 = pattern to match, $3 = replacement) +replace() { + grep $2 $1 >/dev/null + if [ $? -eq 0 ]; then + # Pattern found; replace in file + sed -i "s/$2/$3/g" $1 >/dev/null + fi +} + # Given a filename, a regex pattern to match and a replacement string: # If found, perform replacement, else append file w/replacement on new line. replaceAppend() { @@ -45,26 +61,52 @@ append1() { fi } +# Given a list of strings representing options, display each option +# preceded by a number (1 to N), display a prompt, check input until +# a valid number within the selection range is entered. +selectN() { + for ((i=1; i<=$#; i++)); do + echo $i. ${!i} + done + echo + REPLY="" + while : + do + echo -n "SELECT 1-$#: " + read + if [[ $REPLY -ge 1 ]] && [[ $REPLY -le $# ]]; then + return $REPLY + fi + done +} + echo "Updating dependencies" -apt-get update && sudo apt-get upgrade && sudo apt-get update -apt-get install -y --force-yes git-core build-essential ntp scons python-dev swig python-psutil - -echo "Adding new user loragw, enter it password" -useradd -m loragw -s /bin/bash -passwd loragw -usermod -a -G sudo loragw -cp /etc/sudoers.d/010_pi-nopasswd /etc/sudoers.d/010_loragw-nopasswd -sed -i -- 's/pi/loragw/g' /etc/sudoers.d/010_loragw-nopasswd -cp /home/pi/.profile /home/loragw/ -cp /home/pi/.bashrc /home/loragw/ -chown loragw:loragw /home/loragw/.* -usermod -a -G i2c,spi,gpio loragw +apt-get update && apt-get upgrade -y --force-yes && apt-get update +apt-get install -y --force-yes git-core build-essential ntp scons i2c-tools + +echo "Updating python dependencies" +apt-get install -y --force-yes python-dev swig python-psutil python-rpi.gpio python-pip +python -m pip install --upgrade pip setuptools wheel + +if [[ ! -d /home/loragw ]]; then + echo "Adding new user loragw, enter it password" + useradd -m loragw -s /bin/bash + passwd loragw + usermod -a -G sudo loragw + cp /etc/sudoers.d/010_pi-nopasswd /etc/sudoers.d/010_loragw-nopasswd + sed -i -- 's/pi/loragw/g' /etc/sudoers.d/010_loragw-nopasswd + cp /home/pi/.profile /home/loragw/ + cp /home/pi/.bashrc /home/loragw/ + chown loragw:loragw /home/loragw/.* + usermod -a -G i2c,spi,gpio loragw +fi echo "Enabling Uart, I2C, SPI, Video Memory to 16MB" -replaceAppend /boot/config.txt "^enable_uart.*$" "enable_uart=1" -replaceAppend /boot/config.txt "^dtparam=i2c_arm=.*$" "dtparam=i2c_arm=on" -replaceAppend /boot/config.txt "^dtparam=spi=.*$" "dtparam=spi=on" -replaceAppend /boot/config.txt "^gpu_mem=.*$" "gpu_mem=16" +replaceAppend /boot/config.txt "^.*enable_uart.*$" "enable_uart=1" +replaceAppend /boot/config.txt "^.*dtparam=i2c_arm=.*$" "dtparam=i2c_arm=on" +replaceAppend /boot/config.txt "^.*dtparam=spi=.*$" "dtparam=spi=on" +replaceAppend /boot/config.txt "^.*gpu_mem=.*$" "gpu_mem=16" +replaceAppend /etc/modules "^.*i2c-dev.*$" "i2c-dev" echo -n "Do you want to configure timezone [y/N] " read @@ -73,34 +115,56 @@ if [[ "$REPLY" =~ ^(yes|y|Y)$ ]]; then dpkg-reconfigure tzdata fi -echo -n "Do you want to enable log2ram [y/N] " -read -if [[ "$REPLY" =~ ^(yes|y|Y)$ ]]; then - echo "Setting up log2ram." - git clone https://github.com/azlux/log2ram.git - cd log2ram - chmod +x install.sh uninstall.sh - ./install.sh - ln -s /usr/local/bin/ram2disk /etc/cron.hourly/ +if [[ ! -f /usr/local/bin/log2ram ]]; then + echo -n "Do you want to enable log2ram [y/N] " + read + if [[ "$REPLY" =~ ^(yes|y|Y)$ ]]; then + echo "Setting up log2ram." + git clone https://github.com/azlux/log2ram.git + cd log2ram + chmod +x install.sh uninstall.sh + ./install.sh + ln -s /usr/local/bin/log2ram /etc/cron.hourly/ + echo "cleaning up log rotation" + replace /etc/logrotage.d/rsyslog "^.*daily.*$" " hourly" + replace /etc/logrotage.d/rsyslog "^.*monthly.*$" " daily" + replace /etc/logrotage.d/rsyslog "^.*delaycompress.*$" " " + + echo "forcing one log rotation" + logrotate /etc/logrotate.conf + echo "Please don't forget to adjust the logrotate" + echo "paratemeters in /etc/logrotage.d/* to avoid" + echo "filling up the ramdisk, see README in" + echo "https://github.com/ch2i/LoraGW-Setup/" + echo "" + fi fi # set hostname to loragw-xxyy with xxyy last MAC Address digits set -- `cat /sys/class/net/wlan0/address` IFS=":"; declare -a Array=($*) -HOST=loragw-${Array[4]}${Array[5]} -echo "New hostname will be set to $HOST" -echo -n "OK? [y/N] " -read -if [[ "$REPLY" =~ ^(yes|y|Y)$ ]]; then - echo "hostname is now $HOST" - sudo bash -c "echo $HOST" > /etc/hostname +NEWHOST=loragw-${Array[4]}${Array[5]} + +echo "" +echo "Please select new device name (hostname)" +selectN "Leave as $HOSTNAME" "loragw" "$NEWHOST" +SEL=$? +if [[ $SEL -gt 1 ]]; then + if [[ $SEL == 2 ]]; then + NEWHOST=loragw + fi + sudo bash -c "echo $NEWHOST" > /etc/hostname + replace /etc/hosts "^127.0.1.1.*$HOSTNAME.*$" "127.0.1.1\t$NEWHOST" + echo "New hostname set to $NEWHOST" +else + echo "hostname unchanged" fi echo "Done." echo echo "Settings take effect on next boot." echo "after reboot, login back here with" -echo "ssh loragw@$HOST.local" +echo "ssh loragw@$NEWHOST.local" echo echo -n "REBOOT NOW? [y/N] " read diff --git a/2_Deps.sh b/2_Deps.sh deleted file mode 100755 index aa4bd1c..0000000 --- a/2_Deps.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -MODEL=`cat /proc/device-tree/model` - -echo "This script configures a Raspberry Pi" -echo "as a LoRaWAN Gateway connected to TTN," -echo -echo "It will install the following dependencies" -echo "nodejs, git, pyhton, ntp, scons, ws2812" -echo -echo "Device is $MODEL" -echo -echo "Run time ~10 minutes." -echo -echo -n "CONTINUE? [Y/n] " -read -if [[ "$REPLY" =~ ^(yes|y|Y)$ ]]; then - echo "Canceled." - exit 0 -fi - - -# Given a filename, a regex pattern to match and a replacement string: -# If found, perform replacement, else append file w/replacement on new line. -replaceAppend() { - grep $2 $1 >/dev/null - if [ $? -eq 0 ]; then - # Pattern found; replace in file - sed -i "s/$2/$3/g" $1 >/dev/null - else - # Not found; append on new line (silently) - echo $3 | sudo tee -a $1 >/dev/null - fi -} - -# Given a filename, a regex pattern to match and a string: -# If found, no change, else append file with string on new line. -append1() { - grep $2 $1 >/dev/null - if [ $? -ne 0 ]; then - # Not found; append on new line (silently) - echo $3 | sudo tee -a $1 >/dev/null - fi -} - -# Given a list of strings representing options, display each option -# preceded by a number (1 to N), display a prompt, check input until -# a valid number within the selection range is entered. -selectN() { - for ((i=1; i<=$#; i++)); do - echo $i. ${!i} - done - echo - REPLY="" - while : - do - echo -n "SELECT 1-$#: " - read - if [[ $REPLY -ge 1 ]] && [[ $REPLY -le $# ]]; then - return $REPLY - fi - done -} - -echo "Target board/shield for this $MODEL:" -selectN "CH2i RAK831 Minimal" "CH2i RAK831 with WS2812B Led" "CH2i ic880a" "All other models" -BOARD_TARGET=$? - - -echo -n "Do you want to install I2C OLED [y/N] " -read OLED -if [[ "$OLED" =~ ^(yes|y|Y)$ ]]; then - echo "Reconfiguring Time Zone." - dpkg-reconfigure tzdata -fi - -grep "Pi 3" $MODEL >/dev/null -if [ $? -eq 0 ]; then - echo "Installing nodejs v8 for Raspberry PI 3" - sudo curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - - sudo apt-get install nodejs -fi - -grep "Pi Zero" $MODEL >/dev/null -if [ $? -eq 0 ]; then - echo "Installing nodejs lts for Raspberry PI Zero" - sudo wget -O - https://raw.githubusercontent.com/sdesalas/node-pi-zero/master/install-node-v.lts.sh | bash - append1 /home/loragw/.profile "^.*PATH:/opt/nodejs/bin.*$" "export PATH=$PATH:/opt/nodejs/bin" - append1 /home/loragw/.profile "^.*NODE_PATH=.*$" "NODE_PATH=/opt/nodejs/lib/node_modules" -fi - -# Board has WS1812B LED -if [[ $BOARD_TARGET == 2 ]]; then - echo "Installing WS2812B LED driver" - - echo "Blacklisting snd_bcm2835 module due to WS2812b LED PWM" - append1 /etc/modprobe.d/snd-blacklist.conf "^.*snd_bcm2835.*$" "blacklist snd_bcm2835" - - echo "Installing WS2812B drivers and libraries" - git clone https://github.com/jgarff/rpi_ws281x - cd rpi_ws281x/ - scons - scons deb - sudo dpkg -i libws2811*.deb - sudo cp ws2811.h /usr/local/include/ - sudo cp rpihw.h /usr/local/include/ - sudo cp pwm.h /usr/local/include/ - cd python - python ./setup.py build - sudo python setup.py install - cd - sudo npm install -g --unsafe-perm rpi-ws281x-native - npm link rpi-ws281x-native -fi - -if [[ "$OLED" =~ ^(yes|y|Y)$ ]]; then - echo "Configuring and installing OLED driver" - replaceAppend /boot/config.txt "^dtparam=i2c_arm=.*$" "dtparam=i2c_arm=on,i2c_baudrate=400000" - sudo apt-get install -y --force-yes i2c-tools python-dev python-pip libfreetype6-dev libjpeg-dev build-essential - - echo "Install luma OLED core" - sudo -H pip install --upgrade luma.oled - - echo "Get examples files (and font)" - sudo mkdir -p /usr/share/fonts/truetype/luma - git clone https://github.com/rm-hull/luma.examples.git - sudo cp luma.examples/examples/fonts/*.ttf /usr/share/fonts/truetype/luma/ -fi - - - - diff --git a/2_Setup.sh b/2_Setup.sh index 57f0f2c..4d2192b 100755 --- a/2_Setup.sh +++ b/2_Setup.sh @@ -19,11 +19,11 @@ echo "needed services (Monitor, Oled, GW) at boot" echo echo "Device is $MODEL" echo -echo "Run time ~10 minutes." +echo "Run time ~5 to 15 minutes depending on features." echo echo -n "CONTINUE? [Y/n] " read -if [[ "$REPLY" =~ ^(yes|y|Y)$ ]]; then +if [[ "$REPLY" =~ ^(no|n|N)$ ]]; then echo "Canceled." exit 0 fi @@ -62,6 +62,11 @@ append1() { fi } +# These functions have been copied from excellent Adafruit Read only tutorial +# https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/read-only-fs.sh +# the one inspired by my original article http://hallard.me/raspberry-pi-read-only/ +# That's an excellent demonstration of collaboration and open source sharing +# # Given a list of strings representing options, display each option # preceded by a number (1 to N), display a prompt, check input until # a valid number within the selection range is entered. @@ -83,26 +88,47 @@ selectN() { echo "" echo "Target board/shield for this $MODEL:" -selectN "CH2i RAK831 Minimal" "CH2i RAK831 with WS2812B Led" "CH2i ic880a" "All other models" +selectN "CH2i RAK831 Minimal" "CH2i RAK831 with WS2812B Led" "CH2i ic880a" "IMST Lora Lite (ic880a)" "RAK831 official shield" "All other models" BOARD_TARGET=$? if [[ $BOARD_TARGET == 1 ]]; then GW_RESET_PIN=25 MONITOR_SCRIPT=monitor-ws2812.py export GW_RESET_PIN -elif [[ $BOARD_TARGET == 2 ]]; then +fi +if [[ $BOARD_TARGET == 2 ]]; then GW_RESET_PIN=25 MONITOR_SCRIPT=monitor-ws2812.py export GW_RESET_PIN -elif [[ $BOARD_TARGET == 3 ]]; then +fi +if [[ $BOARD_TARGET == 4 ]]; then + GW_RESET_PIN=5 + export GW_RESET_PIN +fi +if [[ $BOARD_TARGET == 3 ]]; then GW_RESET_PIN=17 MONITOR_SCRIPT=monitor-gpio.py export GW_RESET_PIN fi +if [[ $BOARD_TARGET == 5 ]]; then + GW_RESET_PIN=17 + export GW_RESET_PIN +fi + +if [[ $MONITOR_SCRIPT == "" ]]; then + echo "No monitoring script" +else + echo "Monitor script is $MONITOR_SCRIPT" +fi +echo "GW Reset pin is GPIO$GW_RESET_PIN" echo "" echo -n "Do you want to build Kersing packet forwarder [Y/n] " read BUILD_GW +echo "" +echo -n "Do you want to build legacy packet forwarder [y/N] " +read BUILD_LEGACY + echo "" echo "You can enable monitor service that manage blinking led to" echo "display status and also add button management to shutdown PI" @@ -110,14 +136,15 @@ echo -n "Would you like to enable this [Y/n] " read EN_MONITOR echo "" +echo "If you a OLED display, You can enable OLED service that" +echo "display some system information and LoRaWAN packet info" echo -n "Do you want to install I2C OLED [y/N] " read EN_OLED - echo "" echo -n "Do you want to setup TTN [Y/n] " read EN_TTN -if [[ "$EN_TTN" =~ ^(yes|y|Y)$ ]]; then +if [[ ! "$EN_TTN" =~ ^(no|n|N)$ ]]; then echo "It's now time to create and configure your gateway on TTN" echo "See https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector" @@ -156,13 +183,20 @@ if [[ "$EN_TTN" =~ ^(yes|y|Y)$ ]]; then fi # Set the reset în in startup shell -replace ./start.sh "^.*RESET_BCM_PIN=.*$" "RESET_BCM_PIN=$GW_RESET_PIN" +replace ./start.sh "^.*RESET_BCM_PIN=.*$" "SX1301_RESET_BCM_PIN=$GW_RESET_PIN" grep "Pi\ 3" /proc/device-tree/model >/dev/null if [ $? -eq 0 ]; then - echo "Installing nodejs v8 for Raspberry PI 3" - curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - + echo "Installing nodejs v10 for Raspberry PI 3" + curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - apt-get install nodejs + + # iC880a and RPI 3 Setup Activity LED and Power OFF Led + if [[ $BOARD_TARGET == 3 ]]; then + replaceAppend /boot/config.txt "^dtoverlay=gpio-poweroff.*$" "dtoverlay=gpio-poweroff,gpiopin=24" + replaceAppend /boot/config.txt "^dtoverlay=pi3-act-led.*$" "dtoverlay=pi3-act-led,gpio=23" + fi + fi grep "Pi\ Zero" /proc/device-tree/model >/dev/null @@ -173,14 +207,15 @@ if [ $? -eq 0 ]; then append1 /home/loragw/.profile "^.*NODE_PATH=.*$" "NODE_PATH=/opt/nodejs/lib/node_modules" fi -apt-get -y install protobuf-compiler libprotobuf-dev libprotoc-dev automake libtool autoconf python-dev python-rpi.gpio - +apt-get -y install protobuf-compiler libprotobuf-dev libprotoc-dev automake libtool autoconf # Board has WS1812B LED if [[ $BOARD_TARGET == 2 ]]; then echo "Installing WS2812B LED driver" + cd /home/loragw/ echo "Blacklisting snd_bcm2835 module due to WS2812b LED PWM" + touch /etc/modprobe.d/snd-blacklist.conf append1 /etc/modprobe.d/snd-blacklist.conf "^.*snd_bcm2835.*$" "blacklist snd_bcm2835" echo "Installing WS2812B drivers and libraries" @@ -195,15 +230,19 @@ if [[ $BOARD_TARGET == 2 ]]; then cd python python ./setup.py build python setup.py install - cd + cd /home/loragw/ npm install -g --unsafe-perm rpi-ws281x-native npm link rpi-ws281x-native + # We're sudo reset owner + chown -R loragw:loragw /home/loragw/rpi_ws281x + chown -R loragw:loragw /home/loragw/node_modules fi if [[ "$EN_OLED" =~ ^(yes|y|Y)$ ]]; then echo "Configuring and installing OLED driver" - replaceAppend /boot/config.txt "^dtparam=i2c_arm=.*$" "dtparam=i2c_arm=on,i2c_baudrate=400000" - apt-get install -y --force-yes i2c-tools python-dev python-pip libfreetype6-dev libjpeg-dev build-essential + cd /home/loragw/ + replaceAppend /boot/config.txt "^.*dtparam=i2c_arm=.*$" "dtparam=i2c_arm=on,i2c_baudrate=400000" + apt-get install -y --force-yes libfreetype6-dev libjpeg-dev echo "Install luma OLED core" sudo -H pip install --upgrade luma.oled @@ -211,10 +250,18 @@ if [[ "$EN_OLED" =~ ^(yes|y|Y)$ ]]; then echo "Get examples files (and font)" mkdir -p /usr/share/fonts/truetype/luma git clone https://github.com/rm-hull/luma.examples.git + # We're sudo reset owner + chown -R loragw:loragw /home/loragw/luma.examples cp luma.examples/examples/fonts/*.ttf /usr/share/fonts/truetype/luma/ + + #echo "Build examples files" + #sudo apt install libsdl-dev libportmidi-dev libsdl-ttf2.0-dev libsdl-mixer1.2-dev libsdl-image1.2-dev + #sudo pip install --upgrade setuptools + #cd luma.examples + #udo -H pip install -e . fi -if [[ "$BUILD_GW" =~ ^(yes|y|Y)$ ]]; then +if [[ ! "$BUILD_GW" =~ ^(no|n|N)$ ]]; then echo "Building LoraGW and kersing packet Forwarder" mkdir -p $INSTALL_DIR/dev cd $INSTALL_DIR/dev @@ -302,31 +349,91 @@ if [[ "$BUILD_GW" =~ ^(yes|y|Y)$ ]]; then cp $INSTALL_DIR/dev/packet_forwarder/mp_pkt_fwd/mp_pkt_fwd $INSTALL_DIR/mp_pkt_fwd if [ ! -f $INSTALL_DIR/mp_pkt_fwd ]; then - echo "Oup's, something went wrong, forwarder not found" + echo "Oup's, something went wrong, kersing forwarder not found" echo "please check for any build error" else echo "Build & Installation Completed." - echo "forwrder is located at $INSTALL_DIR/mp_pkt_fwd" + echo "kersing forwarder is located at $INSTALL_DIR/mp_pkt_fwd" echo "" - echo "you can now run the setup script with sudo ./3_Configure.sh" fi fi + +if [[ "$BUILD_LEGACY" =~ ^(yes|y|Y)$ ]]; then + echo "Building legacy packet Forwarder" + + mkdir -p $INSTALL_DIR/dev + mkdir -p $INSTALL_DIR/dev/legacy + cd $INSTALL_DIR/dev/legacy + + # Build legacy loragw library + if [ ! -d lora_gateway ]; then + git clone https://github.com/TheThingsNetwork/lora_gateway.git + pushd lora_gateway + else + pushd lora_gateway + git reset --hard + git pull + fi + sed -i -e 's/PLATFORM= .*$/PLATFORM= imst_rpi/g' ./libloragw/library.cfg + sed -i -e 's/CFG_SPI= .*$/CFG_SPI= native/g' ./libloragw/library.cfg + make + + popd + # Build legacy packet forwarder + if [ ! -d packet_forwarder ]; then + git clone https://github.com/ch2i/packet_forwarder + pushd packet_forwarder + else + pushd packet_forwarder + git pull + git reset --hard + fi + make + + # Copy legacy forwarder where it'll be expected + cp ./poly_pkt_fwd/poly_pkt_fwd $INSTALL_DIR/poly_pkt_fwd + + popd + + if [ ! -f $INSTALL_DIR/poly_pkt_fwd ]; then + echo "Oup's, something went wrong, legacy forwarder not found" + echo "please check for any build error" + else + # Copy things needed at runtime to where they'll be expected + cp $INSTALL_DIR/dev/legacy/packet_forwarder/poly_pkt_fwd/poly_pkt_fwd $INSTALL_DIR/poly_pkt_fwd + echo "Build & Installation Completed." + echo "forwarder is located at $INSTALL_DIR/poly_pkt_fwd" + echo "" + echo "Do you want this forwarder to be run instead" + echo -n "kersing mp_pkt_fwd? [y/N] " + read + if [[ "$REPLY" =~ ^(yes|y|Y)$ ]]; then + replace ./start.sh "^.*mp_pkt_fwd.*$" "./poly_pkt_fwd" + fi + + fi + +fi + # Copying all needed script and system -sudo cp ./oled.py $GW_DIR/ -sudo cp ./monitor-ws2812.py $GW_DIR/ -sudo cp ./monitor-gpio.py $GW_DIR/ -sudo ln -s $GW_DIR/$MONITOR_SCRIPT $GW_DIR/monitor.py -sudo cp ./monitor.service /lib/systemd/system/ -sudo cp ./oled.service /lib/systemd/system/ -sudo cp start.sh $GW_DIR/ - -if [[ "$EN_TTN" =~ ^(yes|y|Y)$ ]]; then +cd /home/loragw/LoraGW-Setup +cp ./oled.py $INSTALL_DIR/ +cp ./monitor-ws2812.py $INSTALL_DIR/ +cp ./monitor-gpio.py $INSTALL_DIR/ +if [[ $MONITOR_SCRIPT != "" ]]; then + ln -s $INSTALL_DIR/$MONITOR_SCRIPT $INSTALL_DIR/monitor.py +fi +cp ./monitor.service /lib/systemd/system/ +cp ./oled.service /lib/systemd/system/ +cp start.sh $INSTALL_DIR/ + +if [[ ! "$EN_TTN" =~ ^(no|n|N)$ ]]; then # script to get config from TTN server python set_config.py # Copy config to running folder - sudo mv global_conf.json $GW_DIR/ + sudo mv global_conf.json $INSTALL_DIR/ # Prepare start forwarder as systemd script sudo cp ./loragw.service /lib/systemd/system/ @@ -339,7 +446,7 @@ if [[ "$EN_TTN" =~ ^(yes|y|Y)$ ]]; then fi -if [[ "$EN_MONITOR" =~ ^(yes|y|Y)$ ]]; then +if [[ ! "$EN_MONITOR" =~ ^(no|n|N)$ ]]; then echo "monitor service enabled!" sudo systemctl enable monitor.service sudo systemctl start monitor.service diff --git a/3_WiFi_AP.sh b/3_WiFi_AP.sh new file mode 100755 index 0000000..484f3ab --- /dev/null +++ b/3_WiFi_AP.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +INSTALL_DIR="/opt/loragw" +MODEL=`cat /proc/device-tree/model` + +if [ $(id -u) -ne 0 ]; then + echo "Installer must be run as root." + echo "Try 'sudo bash $0'" + exit 1 +fi + +echo "This script configures a Raspberry Pi" +echo "as a wifi access point and client" +echo +echo "It will install the following dependencies" +echo "hostapd, dnsmasq and configure SSID / Password" +echo +echo "Device is $MODEL" +echo + +if echo "$MODEL" | grep -q "Zero"; then + echo "Device Match configuration OK"; +else + echo "This model is not supported, this" + echo "script runs only on Pi Zero else" + echo "it will break your network config" + echo "You'll loose network on reboot and" + echo "potentially access to your device" + echo "" + echo "!!! you've been warned !!!" + echo "exiting immediatly to avoid this" + echo "for this PI model use docker mode" + echo "and follow procedure located here" + echo "https://github.com/cjimti/iotwifi" + echo "to install docker then run script" + echo "4_WiFi_Docker.sh of this folder" + + + exit 0 +fi + + +echo "Run time ~1 minute. Reboot required." +echo +echo -n "CONTINUE? [Y/n] " +read +if [[ "$REPLY" =~ ^(no|n|N)$ ]]; then + echo "Canceled." + exit 0 +fi + +# These functions have been copied from excellent Adafruit Read only tutorial +# https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/read-only-fs.sh +# the one inspired by my original article http://hallard.me/raspberry-pi-read-only/ +# That's an excellent demonstration of collaboration and open source sharing +# +# Given a filename, a regex pattern to match and a replacement string: +# Replace string if found, else no change. +# (# $1 = filename, $2 = pattern to match, $3 = replacement) +replace() { + grep $2 $1 >/dev/null + if [ $? -eq 0 ]; then + # Pattern found; replace in file + sed -i "s/$2/$3/g" $1 >/dev/null + fi +} + +# Given a filename, a regex pattern to match and a replacement string: +# If found, perform replacement, else append file w/replacement on new line. +replaceAppend() { + grep $2 $1 >/dev/null + if [ $? -eq 0 ]; then + # Pattern found; replace in file + sed -i "s/$2/$3/g" $1 >/dev/null + else + # Not found; append on new line (silently) + echo $3 | sudo tee -a $1 >/dev/null + fi +} + +# Given a filename, a regex pattern to match and a string: +# If found, no change, else append file with string on new line. +append1() { + grep $2 $1 >/dev/null + if [ $? -ne 0 ]; then + # Not found; append on new line (silently) + echo $3 | sudo tee -a $1 >/dev/null + fi +} + + +echo "" +echo "Enter SSID you want to see for your WiFi AP" +echo -n "default is set to $HOSTNAME : " +read SSID +if [[ $SSID == "" ]]; then + SSID=$HOSTNAME +fi + +echo "" +echo "Enter password you want for you access point" +echo -n "default is set $SSID : " +read PSK +if [[ $PSK == "" ]]; then + PSK=$SSID +fi + +echo "" +echo "Please enter WiFi country code" +echo -n "default is set to FR : " +read CCODE + +echo "" +echo "Setting up WiFi access point with" +echo "SSID : $SSID" +echo "PSK : $PSK" + +sudo apt-get install -y hostapd dnsmasq + +# Set the SSID/PSK +echo "Replacing SSID / PASK in hostapd.conf" +replace ./config/hostapd.conf "^.*_AP_SSID_.*$" "ssid=$SSID" +replace ./config/hostapd.conf "^.*_AP_PASSWORD_.*$" "wpa_passphrase=$PSK" +if [[ $CCODE != "" ]]; then + echo "Setting default country code to $CCCODE in hostapd.conf" + replace ./config/hostapd.conf "^.*country_code=.*$" "country_code=$CCODE" +fi + +# Copy configuration files (save orgininal files) +cp ./config/90-wireless.rules /etc/udev/rules.d/ +cp ./config/hostapd.conf /etc/hostapd/ +cp ./config/dnsmasq.conf /etc/ +cp /etc/network/interfaces /etc/network/interfaces.old +cp ./config/interfaces /etc/network/ + +echo "Setting default hostapd config file" +append1 /etc/default/hostapd "^.*DAEMON_CONF=.*$" "DAEMON_CONF=\"/etc/hostapd/hostapd.conf\"" + +# disable dhcpcd service +update-rc.d dhcpcd disable + +# Fix bootup (save orgininal file) +cp /etc/rc.local /etc/rc.local.old +cp ./config/rc.local /etc/ + +echo "Done." +echo +echo "Settings take effect on next boot." +echo "after reboot, login back here with" +echo "ssh loragw@$HOSTNAME.local" +echo +echo -n "REBOOT NOW? [y/N] " +read +if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then + echo "Exiting without reboot." + exit 0 +fi +echo "Reboot started..." +reboot +exit 0 + + + diff --git a/4_WiFi_Docker.sh b/4_WiFi_Docker.sh new file mode 100755 index 0000000..5a474e1 --- /dev/null +++ b/4_WiFi_Docker.sh @@ -0,0 +1,124 @@ +#!/bin/bash + +INSTALL_DIR="/opt/loragw" +MODEL=`cat /proc/device-tree/model` + +if [ $(id -u) -ne 0 ]; then + echo "Installer must be run as root." + echo "Try 'sudo bash $0'" + exit 1 +fi + +echo "This script configures a Raspberry Pi" +echo "as a wifi access point and client" +echo +echo "It will install a docker container doing" +echo "all the necessary staff, please see" +echo "https://github.com/cjimti/iotwifi" +echo +echo "Device is $MODEL" +echo + +echo "Run time ~3 minutes. Reboot required." +echo +echo -n "CONTINUE? [Y/n] " +read +if [[ "$REPLY" =~ ^(no|n|N)$ ]]; then + echo "Canceled." + exit 0 +fi + +# These functions have been copied from excellent Adafruit Read only tutorial +# https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/read-only-fs.sh +# the one inspired by my original article http://hallard.me/raspberry-pi-read-only/ +# That's an excellent demonstration of collaboration and open source sharing +# +# Given a filename, a regex pattern to match and a replacement string: +# Replace string if found, else no change. +# (# $1 = filename, $2 = pattern to match, $3 = replacement) +replace() { + grep $2 $1 >/dev/null + if [ $? -eq 0 ]; then + # Pattern found; replace in file + sed -i "s/$2/$3/g" $1 >/dev/null + fi +} + +echo "" +echo "Enter SSID you want to see for your WiFi AP" +echo -n "default is set to $HOSTNAME : " +read SSID +if [[ $SSID == "" ]]; then + SSID=$HOSTNAME +fi + +echo "" +echo "Enter password you want for you access point" +echo -n "default is set $SSID : " +read PSK +if [[ $PSK == "" ]]; then + PSK=$SSID +fi + +echo "" +echo "Please enter WiFi country code" +echo -n "default is set to FR : " +read CCODE + +echo "" +echo "Setting up WiFi access point with" +echo "SSID : $SSID" +echo "PSK : $PSK" + +echo "installing dpendencies" +echo "Docker install script" +curl -sSL https://get.docker.com | sh +sudo usermod -aG docker loragw + +echo "ull the IOT Wifi Docker Image" +docker pull cjimti/iotwifi + +# Set the SSID/PSK +echo "Replacing SSID / PASK in hostapd.conf" +replace ./wificfg.json "^.*_AP_SSID_.*$" "$SSID" +replace ./wificfg.json "^.*_AP_PASSWORD_.*$" "$PSK" + +# Copy config file to install folder +sudo mv ./wificfg.json $INSTALL_DIR/ +sudo ln -s $INSTALL_DIR/wificfg.json ./ + +if [[ $CCODE != "" ]]; then + echo "Setting default country code to $CCCODE in hostapd.conf" + replace /etc/wpa_supplicant/wpa_supplicant.conf "^.*country=.*$" "country=$CCODE" +fi + + +# prevent wpa_supplicant from starting on boot it will be used by docker +sudo systemctl mask wpa_supplicant.service +# rename wpa_supplicant on the host to ensure that it is not used. +sudo mv /sbin/wpa_supplicant /sbin/wpa_supplicant.old +# kill any running processes named wpa_supplicant +sudo pkill wpa_supplicant + +echo "starting docker as a service" +docker run --restart unless-stopped -d --privileged --net host \ + -v /opt/loragw//wificfg.json:/cfg/wificfg.json \ + -v /etc/wpa_supplicant/wpa_supplicant.conf:/etc/wpa_supplicant/wpa_supplicant.conf \ + cjimti/iotwifi + +echo "Done." +echo +echo "Settings take effect on next boot." +echo "after reboot, login back here with" +echo "ssh loragw@$HOSTNAME.local" +echo +echo -n "REBOOT NOW? [y/N] " +read +if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then + echo "Exiting without reboot." + exit 0 +fi +echo "Reboot started..." +reboot +exit 0 + diff --git a/5_GPS.sh b/5_GPS.sh new file mode 100755 index 0000000..d02690d --- /dev/null +++ b/5_GPS.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +INSTALL_DIR="/opt/loragw" +MODEL=`cat /proc/device-tree/model` + +if [ $(id -u) -ne 0 ]; then + echo "Installer must be run as root." + echo "Try 'sudo bash $0'" + exit 1 +fi + +echo "This script configures a Raspberry Pi" +echo "GPS for TTN gateway" +echo +echo "Device is $MODEL" +echo + +echo "Run time ~1 minute. Reboot required." +echo +echo -n "CONTINUE? [Y/n] " +read +if [[ "$REPLY" =~ ^(no|n|N)$ ]]; then + echo "Canceled." + exit 0 +fi + +echo "" +echo "Enter GPS device to use" +echo -n "default is set to /dev/ttyS0 : " +read DEVGPS +if [[ $DEVGPS == "" ]]; then + DEVGPS="/dev/ttyS0" +fi + +sudo systemctl stop serial-getty@ttyS0.service +sudo systemctl disable serial-getty@ttyS0.service + +echo +echo "now change the file $INSTALL_DIR/local_conf.json" +echo "and check that the following lines exist" +echo +echo '"fake_gps": false,' +echo '"gps": true,' +echo '"gps_tty_path": "'$DEVGPS'"' +echo +echo "you may also need to add theese lines" +echo "to /boot/config.txt (example for PI 3)" +echo +echo "dtoverlay = pi3-miniuart-bt" +echo "enable_uart=1" +echo +echo "then reboot the Raspberry Pi" + diff --git a/README.md b/README.md index 3ab041c..889892c 100644 --- a/README.md +++ b/README.md @@ -80,216 +80,42 @@ So please **for security reasons, you should change this default password** passwd ``` -```shell -sudo apt-get update && sudo apt-get upgrade -sudo apt-get install git-core build-essential ntp scons python-dev swig python-psutil -``` - -If the 2nd command fire the following error (always happen with latest rasbian because it updates kernel and co) -then just **reboot** and restart the 2 commands above. - -``` -Reading package lists... Done -Building dependency tree -Reading state information... Done -Package python-psutil is not available, but is referred to by another package. -This may mean that the package is missing, has been obsoleted, or -is only available from another source - -Package ntp is not available, but is referred to by another package. -This may mean that the package is missing, has been obsoleted, or -is only available from another source - -Package python-dev is not available, but is referred to by another package. -This may mean that the package is missing, has been obsoleted, or -is only available from another source -However the following packages replace it: - python - -E: Unable to locate package git-core -E: Package 'ntp' has no installation candidate -E: Unable to locate package scons -E: Package 'python-dev' has no installation candidate -E: Unable to locate package swig -E: Package 'python-psutil' has no installation candidate -``` - -## Create a new user account (loragw). - -This `loragw` account will be used instead of default existing `pi` account for security reasons. -```shell -sudo useradd -m loragw -s /bin/bash -``` - -Type a suitable password for the `loragw` account. -```shell -sudo passwd loragw -``` - -Add the `loragw` user to the group `sudo` and allow sudo command with no password -```shell -sudo usermod -a -G sudo loragw -sudo cp /etc/sudoers.d/010_pi-nopasswd /etc/sudoers.d/010_loragw-nopasswd -sudo sed -i -- 's/pi/loragw/g' /etc/sudoers.d/010_loragw-nopasswd -``` - -copy default `pi` profile to `loragw` -```shell -sudo cp /home/pi/.profile /home/loragw/ -sudo cp /home/pi/.bashrc /home/loragw/ -sudo chown loragw:loragw /home/loragw/.* -``` +### Launch PI configuration script -Give `loragw` access to hardware I2C, SPI and GPIO -```shell -sudo usermod -a -G i2c,spi,gpio loragw -``` +This [1_Pi_Config.sh](https://github.com/ch2i/LoraGW-Setup/blob/master/1_Pi_Config.sh) script will prepare your Pi environnment, create and configure a loragw user, add access to SPI, I2C, Uart. It will reduce video memory to 16MB to allow max memory for the stuff need to be done. +It also enable excellent [log2ram](https://github.com/azlux/log2ram) SD card preservation. -Now do some system configuration with `raspi-config` tool (bold are mandatory) ```shell -sudo raspi-config +wget https://raw.githubusercontent.com/ch2i/LoraGW-Setup/master/1_Pi_Config.sh +chmod ug+x 1_Pi_Config.sh +sudo ./1_Pi_Config.sh ``` - - network options, change hostname (loragw for example) - - localization options, change keyboard layout - - localization options, change time zone - - **interfacing options, enable SPI, I2C** Serial and SSH (if not already done) - - advanced options, expand filesystem - - advanced options, reduce video memory split set to 16M - -then do not when asked. - -## Optionnal, Install log2ram this will preserve your SD card -```shell -git clone https://github.com/azlux/log2ram.git -cd log2ram -chmod +x install.sh uninstall.sh -sudo ./install.sh -sudo ln -s /usr/local/bin/ram2disk /etc/cron.hourly/ -``` - - -## Now reboot - -**Reboot** -```shell -sudo reboot -``` ## Reconnect after reboot -Log back with `loragw` user and if you changed hostname to loragw, use this command -```shell -ssh loragw@loragw.local -``` - - -## Install nodejs - -### For Pi Zero (see below for PI3) -``` -sudo wget -O - https://raw.githubusercontent.com/sdesalas/node-pi-zero/master/install-node-v.lts.sh | bash -``` - -this will fire some error on unlink, but don't worry, that's ok because it's the first install. - -Add the following to the end of your `~/.profile` file with `nano ~/.profile` -``` -export PATH=$PATH:/opt/nodejs/bin -export NODE_PATH=/opt/nodejs/lib/node_modules -``` - -then **logout (CTRL-d) and log back** with `loragw` user* so new profile is loaded. +Log back with `loragw` user and if you changed hostname to loragw-xxyy, use this command ```shell -logout -``` - -### For Pi 3 (see above for PI Zero) -You can select and change nodejs version by changing for example `setup_8.x` to `setup_7.x` -``` -sudo curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - -sudo apt-get install nodejs +ssh loragw@loragw-xxyy.local ``` -## Install WS2812 driver for onboard LED (for RAK831 shield only) - -The onboard WS2812 library and the Raspberry Pi audio both use the PWM, they cannot be used together. You will need to blacklist the Broadcom audio kernel module by editing a file -``` -echo "blacklist snd_bcm2835" | sudo tee --append /etc/modprobe.d/snd-blacklist.conf -``` - -### Install WS2812 led driver (for RAK831 shield only) -``` -git clone https://github.com/jgarff/rpi_ws281x -cd rpi_ws281x/ -scons -scons deb -sudo dpkg -i libws2811*.deb -sudo cp ws2811.h /usr/local/include/ -sudo cp rpihw.h /usr/local/include/ -sudo cp pwm.h /usr/local/include/ -``` - -### Install WS2812 python wrapper (for RAK831 shield only) -``` -cd python -python ./setup.py build -``` - -### Install WS2812 python library (for RAK831 shield only) -``` -sudo python setup.py install -``` - -### Install NodeJS version of WS2812 driver (for RAK831 shield only) -``` -cd -sudo npm install -g --unsafe-perm rpi-ws281x-native -npm link rpi-ws281x-native -``` - -## Install Python I2C/SPI OLED library (if you want to use OLED dispay) - -Optionnaly you can add OLED to display usefull informations on it. Please look at this [documentation](https://github.com/ch2i/LoraGW-Setup/blob/master/doc/DisplayOled.md) for more informations - -## Get CH2i Gateway Install repository +### Get CH2i Gateway Install repository ``` git clone https://github.com/ch2i/LoraGW-Setup -``` - -### Test WS2812 LED if you have any, in python or nodejs -Check that led color match the color displayed on console because on some WS2812B led, Red and Green could be reversed. -``` cd LoraGW-Setup -sudo ./testled.py -sudo ./testled.js -``` +``` -## Build and setup Packet Forwarder +## Configure Gateway on TTN console -New Multi-protocol Packet Forwarder by Jac @Kersing (thanks to @jpmeijers for scripting stuff) -Now build the whole thing, time to get a(nother) coffe, it can take 10/15 minutes! -``` -sudo ./build.sh -``` +Now you need to register your new GW on TTN before next step, see [gateway registration](https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector), the GW_ID and GW_KEY will be asked by the script -## Build and setup legacy Packet Forwarder (optionnal) +### Then launch script to install all stuff -If you really want to use the legacy packet forwarder you can launch this script. Both can be compiled on the same target, no problem, see below how to setup the legacy -``` -sudo ./build_legacy.sh +```shell +sudo ./2_Setup.sh ``` -## Configure Gateway on TTN console - -Now you need to register your new GW on ttn before next step, see [gateway registration](https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector), fill the GW_ID and GW_KEY when running - -## Launch TTN gateway configuration -This script will configure forwarder and all needed configuration -``` -sudo ./setup.sh -``` That's it, If you are using PI Zero [shield](https://github.com/hallard/RAK831-Zero), the 2 LED should be blinking green and you should be able to see your brand new gateway on TTN @@ -303,6 +129,16 @@ sudo reboot ## LED Blinking colors (RAK831 Shied with 2 WS2812B Leds) +WS2812B driver use DMA channel, and with new Raspbian version, using DMA 5 will corrupt your SD card. see this [issue](https://github.com/jgarff/rpi_ws281x/issues/224). It's now solved but if you have old GW with old scripts, be sure to update the line of script `/opt/loragw/monitor_ws2812.py` from +```python +strip = Adafruit_NeoPixel(2, gpio_led, 800000, 5, False, 64, 0, ws.WS2811_STRIP_GRB) +``` + +to (using DMA channel 10 instead of 5) +```python +strip = Adafruit_NeoPixel(2, gpio_led, 800000, 10, False, 64, 0, ws.WS2811_STRIP_GRB) +``` + ### LED 1 - green => connected to Internet @@ -336,22 +172,41 @@ You can change LED code behaviour at the end of script `/opt/loragw/monitor.py` ## Shutdown You can press (and let it pressed) the switch push button, leds well become RED and after 2s start blinking in blue. If you release button when they blink blue, the Pi will initiate a shutdown. So let it 30s before removing power. -### Shutdown LED display (for iC880a only) +### Shutdown LED display (for RPI 3 and iC880a only) -If you have a raspberry PI with this [IC880A shield](https://github.com/ch2i/iC880A-Raspberry-PI), and if you modded the `/boot/config.txt` file with following lines added into: +If you have a raspberry PI 3 with this [iC880A shield](https://github.com/ch2i/iC880A-Raspberry-PI), then the `/boot/config.txt` file has been enhanced with the following lines: ``` # When system if Halted/OFF Light Green LED dtoverlay=gpio-poweroff,gpiopin=24 ``` -then the Green LED (gpio24) will stay on when you can remove the power of the gateway. It's really a great indicator. +The Green LED (gpio24) will stay on when you can remove the power of the gateway. It's really a great indicator. You can also select which GPIO LED is used to replace activity LED if you need it. ``` # Activity LED dtoverlay=pi3-act-led,gpio=23 ``` -then the Red LED (gpio23) will blink on activity. +The Red LED (gpio23) will blink on activity. + +### Shutdown or Activity LED (for RPI Zero Shield V1.5+) + +If you have a raspberry PI Zero with this RAK831, then you can change the `/boot/config.txt` file to choose one of the two following features: + +``` +# When system is Halted/OFF Light Green LED +dtoverlay=gpio-poweroff,gpiopin=26 +``` +The Green LED (gpio26) will stay on when you can remove the power of the gateway. It's really a great indicator. + +You can also choose select this LED to replace activity LED if you need it. +``` +# Activity LED +dtparam=act_led_gpio=26 +``` +The Greend LED (gpio26) will blink on activity. + +You can select only one of the 2 options, not both at the same time. ## Detailled information @@ -437,7 +292,12 @@ Jan 22 01:01:11 loragw loragw[240]: 01:01:11 INFO: [TTN] send status success fo ``` -### Use legacy Packet Forwarder +### Use legacy Packet Forwarder (not needed) + +First build it +``` +./build_legacy.sh +``` If you want to use the legacy packet forwarder, you'll need to change file `/opt/loragw/start.sh` to replace the last line @@ -454,6 +314,59 @@ sudo systemctl stop loragw sudo systemctl start loragw ``` +## Adjust log2ram + +if you chose log2ram to reduce SD card write, you need to change some log file rotation to avoid RAM Disk to be full. + +For this you need to edit each file in `/etc/logrotate.d/`, and on each file: + +- remove line(s) containing `delaycompress` (this avoid uncompressed old log) +- change line(s) containing `rotate n` by rotate 12 (this this the max log file history) +- change line(s) containing `daily` by `hourly` (rotate log each hour) +- change line(s) containing `monthly` by `daily` (rotate log each day) + +In this case we got last 12H with 1 file per hour. Of course, you can adjust these paramaters to feet you need, it's just an example, + +file `/etc/logrotate.d/rsyslog` + +``` +/var/log/syslog +{ + rotate 12 + hourly + missingok + notifempty + compress + postrotate + invoke-rc.d rsyslog rotate > /dev/null + endscript +} + +/var/log/mail.info +/var/log/mail.warn +/var/log/mail.err +/var/log/mail.log +/var/log/daemon.log +/var/log/kern.log +/var/log/auth.log +/var/log/user.log +/var/log/lpr.log +/var/log/cron.log +/var/log/debug +/var/log/messages +{ + rotate 12 + hourly + missingok + notifempty + compress + sharedscripts + postrotate + invoke-rc.d rsyslog rotate > /dev/null + endscript +} + +``` # And here is the final result diff --git a/build.sh b/build.sh deleted file mode 100755 index 215ff15..0000000 --- a/build.sh +++ /dev/null @@ -1,102 +0,0 @@ -#! /bin/bash - -INSTALL_DIR="/opt/loragw" - -mkdir -p $INSTALL_DIR/dev -cd $INSTALL_DIR/dev - -if [ ! -d lora_gateway ]; then - git clone https://github.com/kersing/lora_gateway.git || { echo 'Cloning lora_gateway failed.' ; exit 1; } -else - cd lora_gateway - git reset --hard - git pull - cd .. -fi - -if [ ! -d paho.mqtt.embedded-c ]; then - git clone https://github.com/kersing/paho.mqtt.embedded-c.git || { echo 'Cloning paho mqtt failed.' ; exit 1; } -else - cd paho.mqtt.embedded-c - git reset --hard - git pull - cd .. -fi - -if [ ! -d ttn-gateway-connector ]; then - git clone https://github.com/kersing/ttn-gateway-connector.git || { echo 'Cloning gateway connector failed.' ; exit 1; } -else - cd ttn-gateway-connector - git reset --hard - git pull - cd .. -fi - -if [ ! -d protobuf-c ]; then - git clone https://github.com/kersing/protobuf-c.git || { echo 'Cloning protobuf-c failed.' ; exit 1; } -else - cd protobuf-c - git reset --hard - git pull - cd .. -fi - -if [ ! -d packet_forwarder ]; then - git clone https://github.com/kersing/packet_forwarder.git || { echo 'Cloning packet forwarder failed.' ; exit 1; } -else - cd packet_forwarder - git reset --hard - git pull - cd .. -fi - -if [ ! -d protobuf ]; then - git clone https://github.com/google/protobuf.git || { echo 'Cloning protobuf failed.' ; exit 1; } -else - cd protobuf - git reset --hard - git pull - 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 - -cd $INSTALL_DIR/dev/protobuf-c -./autogen.sh -./configure -make protobuf-c/libprotobuf-c.la -mkdir bin -./libtool install /usr/bin/install -c protobuf-c/libprotobuf-c.la `pwd`/bin -rm -f `pwd`/bin/*so* - -cd $INSTALL_DIR/dev/paho.mqtt.embedded-c/ -make -make install - -cd $INSTALL_DIR/dev/ttn-gateway-connector -cp config.mk.in config.mk -make -cp bin/libttn-gateway-connector.so /usr/lib/ - -cd $INSTALL_DIR/dev/packet_forwarder/mp_pkt_fwd/ -make - -# 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 - -if [ ! -f $INSTALL_DIR/mp_pkt_fwd ]; then - echo "Oup's, something went wrong, forwarder not found" - echo "please check for any build error" -else - echo "Build & Installation Completed." - echo "forwrder is located at $INSTALL_DIR/mp_pkt_fwd" - echo "" - echo "you can now run the setup script with sudo ./setup.sh" -fi - diff --git a/config/90-wireless.rules b/config/90-wireless.rules new file mode 100644 index 0000000..3a538c5 --- /dev/null +++ b/config/90-wireless.rules @@ -0,0 +1 @@ +ACTION=="add|change", SUBSYSTEM=="ieee80211", KERNEL=="phy0", RUN+="/sbin/iw phy %k interface add ap0 type __ap" diff --git a/config/dnsmasq.conf b/config/dnsmasq.conf new file mode 100644 index 0000000..ca91c92 --- /dev/null +++ b/config/dnsmasq.conf @@ -0,0 +1,25 @@ +interface=lo,ap0 +no-dhcp-interface=lo,wlan0 +bind-interfaces +server=8.8.8.8 +domain-needed +bogus-priv + +# You can change this to another network +dhcp-range=192.168.50.50,192.168.50.100,12h + +# if you have read only FS best to put in tmp area +#dhcp-leasefile=/tmp/dnsmasq.leases + +# if you want to to some rediection +#address=/*.apple.com/192.168.50.1 +#address=/*.icloud.com/192.168.50.1 +#address=/#/192.168.50.1 + +###### logging ############ +# own logfile +#log-facility=/var/log/dnsmasq.log +# log-async +# log dhcp infos +#log-dhcp +# debugging dns \ No newline at end of file diff --git a/config/hostapd.conf b/config/hostapd.conf new file mode 100644 index 0000000..a0ddc8b --- /dev/null +++ b/config/hostapd.conf @@ -0,0 +1,16 @@ +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 +interface=ap0 +driver=nl80211 +ssid=_AP_SSID_ +hw_mode=g +channel=9 +wmm_enabled=0 +macaddr_acl=0 +auth_algs=1 +wpa=2 +wpa_passphrase=_AP_PASSWORD_ +wpa_key_mgmt=WPA-PSK +wpa_pairwise=TKIP CCMP +rsn_pairwise=CCMP +country_code=FR diff --git a/config/interfaces b/config/interfaces new file mode 100644 index 0000000..3787e6e --- /dev/null +++ b/config/interfaces @@ -0,0 +1,18 @@ +# Include files from /etc/network/interfaces.d: +source-directory /etc/network/interfaces.d + +auto lo +auto ap0 +auto wlan0 +iface lo inet loopback + +allow-hotplug wlan0 +iface wlan0 inet manual + wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf +iface wlan0 inet dhcp + +allow-hotplug ap0 +iface ap0 inet static + address 192.168.50.1 + netmask 255.255.255.0 + hostapd /etc/hostapd/hostapd.conf diff --git a/config/rc.local b/config/rc.local new file mode 100755 index 0000000..0ba83b4 --- /dev/null +++ b/config/rc.local @@ -0,0 +1,29 @@ +#!/bin/sh -e +# +# rc.local +# +# This script is executed at the end of each multiuser runlevel. +# Make sure that the script will "exit 0" on success or any other +# value on error. +# +# In order to enable or disable this script just change the execution +# bits. +# +# By default this script does nothing. + +ifdown --force wlan0 && ifdown --force ap0 && ifup ap0 && ifup wlan0 +sysctl -w net.ipv4.ip_forward=1 +iptables -t nat -A POSTROUTING -s 192.168.50.0/24 ! -d 192.168.50.0/24 -j MASQUERADE +systemctl restart dnsmasq +iwconfig wlan0 power off + +# Print the IP address +_IP=$(hostname -I) || true +if [ "$_IP" ]; then + printf "My IP address is %s\n" "$_IP" +fi + +exit 0 + + + diff --git a/doc/AccessPoint.md b/doc/AccessPoint.md index 644bac6..e6107d4 100644 --- a/doc/AccessPoint.md +++ b/doc/AccessPoint.md @@ -21,7 +21,7 @@ ACTION=="add|change", SUBSYSTEM=="ieee80211", KERNEL=="phy0", RUN+="/sbin/iw phy ## Install the packages you need for DNS, Access Point and Firewall rules. ``` -sudo apt-get install hostapd dnsmasq iptables-persistent +sudo apt-get install -y hostapd dnsmasq iptables-persistent ``` ## Configure the DNS server @@ -80,7 +80,7 @@ Replace `_AP_SSID_` with the SSID you want for your access point. Replace `_AP_P Change also `country_code` to your own country -### Edit the file `/etc/hostapd/hostapd.conf` to enable service to start correctly +### Edit the file `/etc/default/hostapd` to enable service to start correctly ``` #DAEMON_OPTS=" -f /tmp/hostapd.log" @@ -145,13 +145,34 @@ Make sure do disable dhcpcd with sudo update-rc.d dhcpcd disable ``` -Edit `/etc/rc.local` and add the following lines just before `exit 0` +Edit `/etc/rc.local` and add the following lines just before `# Print the IP Address` ```shell ifdown --force wlan0 && ifdown --force ap0 && ifup ap0 && ifup wlan0 sysctl -w net.ipv4.ip_forward=1 iptables -t nat -A POSTROUTING -s 192.168.50.0/24 ! -d 192.168.50.0/24 -j MASQUERADE systemctl restart dnsmasq +iwconfig wlan0 power off ``` +## Optional, add AP display on OLED software +If you have enabled OLED, you may need to change the following line in `/opt/loragw/oled.py` according to the connected network interface you have to add the ap0 interface + +Mine is wlan0 for WiFi and ap0 for WiFi [access point](https://github.com/ch2i/LoraGW-Setup/blob/master/doc/AccessPoint.md) +```python +draw.text((col1, line1),"Host :%s" % socket.gethostname(), font=font10, fill=255) +draw.text((col1, line2), lan_ip("wlan0"), font=font10, fill=255) +draw.text((col1, line3), network("wlan0"), font=font10, fill=255) +draw.text((col1, line4), lan_ip("uap0"), font=font10, fill=255) +draw.text((col1, line5), network("uap0"), font=font10, fill=255) +``` + +if for example it's running from RPI 3 with eth0 code could be +```python +draw.text((col1, line1),"Host :%s" % socket.gethostname(), font=font10, fill=255) +draw.text((col1, line2), lan_ip("eth0"), font=font10, fill=255) +draw.text((col1, line3), network("eth0"), font=font10, fill=255) +draw.text((col1, line4), lan_ip("ap0"), font=font10, fill=255) +draw.text((col1, line5), network("ap0"), font=font10, fill=255) +``` diff --git a/loragw.service b/loragw.service index 0990254..cf30aaf 100644 --- a/loragw.service +++ b/loragw.service @@ -1,5 +1,7 @@ [Unit] Description=Lora Gateway +Requires=network-online.target +After=network-online.target [Service] WorkingDirectory=/opt/loragw/ diff --git a/monitor-gpio-helium.py b/monitor-gpio-helium.py new file mode 100755 index 0000000..1d9281b --- /dev/null +++ b/monitor-gpio-helium.py @@ -0,0 +1,160 @@ +#!/usr/bin/python +# ********************************************************************************** +# monitor-gpio-helium.py +# ********************************************************************************** +# Script for monitoring LoraWAN Gateways based on small Linux computers +# it's lighing some LEDs depending on status and process +# it's also monitoring a push button to do a clean shutdown +# this one monitor also status of helium gateway service +# +# Written by Charles-Henri Hallard http://ch2i.eu +# +# History : V1.00 2017-12-22 - Creation +# +# All text above must be included in any redistribution. +# +# ********************************************************************************** + +import RPi.GPIO as GPIO +import thread +import time +import os +import urllib +import sys +import signal +import subprocess +import select +from systemd import journal + +gpio_blu = 4 +gpio_yel = 18 +gpio_red = 23 +gpio_grn = 24 + +internet = False # True if internet connected +pktfwd = False # True if packet forwarder is started +helium = False # True if helium_gateway is running + +def signal_handler(signal, frame): + GPIO.output(gpio_blu, GPIO.LOW) + GPIO.output(gpio_yel, GPIO.LOW) + GPIO.output(gpio_red, GPIO.LOW) + GPIO.output(gpio_grn, GPIO.LOW) + sys.exit(0) + + +def check_process(process): + proc = subprocess.Popen(["if pgrep " + process + " >/dev/null 2>&1; then echo '1'; else echo '0'; fi"], stdout=subprocess.PIPE, shell=True) + (ret, err) = proc.communicate() + ret = int(ret) +# print ret + if ret==1: + return True + else: + return False + +def check_inet(delay): + global internet + global pktfwd + global helium + + while True: + #print "check Internet" + try: + url = "https://www.google.com" + urllib.urlopen(url) + internet = True + except: + internet = False + + # Check packet forwarder + pktfwd = check_process("mp_pkt_fwd") or check_process("poly_pkt_fwd") or check_process("lora_pkt_fwd") + # Check helium gateway + helium = check_process("helium_gateway") + + time.sleep(delay) + +def check_packet(pool_delay): + + # Create a systemd.journal.Reader instance + j = journal.Reader() + # Set the reader's default log level + j.log_level(journal.LOG_INFO) + # Filter log entries + j.add_match(_SYSTEMD_UNIT="helium_gateway.service", SYSLOG_IDENTIFIER="helium_gateway") + j.seek_tail() + j.get_previous() + p = select.poll() + # Register the journal's file descriptor with the polling object. + journal_fd = j.fileno() + poll_event_mask = j.get_events() + p.register(journal_fd, poll_event_mask) + + # Poll for new journal entries every 250ms + while True: + if p.poll(pool_delay): + if j.process() == journal.APPEND: + for entry in j: + try: + # message starts with what we call packet + msg = str(entry['MESSAGE']) + if msg.startswith(('uplink','downlink','join')): + GPIO.output(gpio_grn, GPIO.HIGH) + time.sleep(.3) + except: + pass + GPIO.output(gpio_grn, GPIO.LOW) + +# Use the Broadcom SOC Pin numbers +# Setup the Pin with Internal pullups enabled and PIN in reading mode. +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) +GPIO.setup(gpio_blu, GPIO.OUT) +GPIO.setup(gpio_yel, GPIO.OUT) +GPIO.setup(gpio_red, GPIO.OUT) +GPIO.setup(gpio_grn, GPIO.OUT) + +signal.signal(signal.SIGINT, signal_handler) + +try: + thread.start_new_thread( check_inet, (5, ) ) +except: + print "Error: unable to start check_inet thread" + +try: + thread.start_new_thread( check_packet, (250, ) ) +except: + print "Error: unable to start check_packet thread" + +# Now wait! +while True: + # Light off all LEDS + led_blu = GPIO.LOW + led_yel = GPIO.LOW + led_red = GPIO.LOW + + # Blue Internet OK else light RED + if internet == True: + led_blu = GPIO.HIGH + else: + led_red = GPIO.HIGH + + # Yellow forwarders OK else light RED + if pktfwd == True and helium == True: + led_yel = GPIO.HIGH + else: + led_red = GPIO.HIGH + + # Blink Blue (Internet) + GPIO.output(gpio_blu, led_blu) + time.sleep(.2) + GPIO.output(gpio_blu, GPIO.LOW) + time.sleep(.8) + + # Blink Yellow (Forwarders) + GPIO.output(gpio_yel, led_yel) + time.sleep(.2) + GPIO.output(gpio_yel, GPIO.LOW) + time.sleep(.8) + + diff --git a/monitor-gpio.py b/monitor-gpio.py index cd54580..9fd1fbe 100755 --- a/monitor-gpio.py +++ b/monitor-gpio.py @@ -88,7 +88,7 @@ def check_inet(delay): # Check WiFi AP mode and packet forwarder #hostapd = check_process("hostapd") - pktfwd = check_process("mp_pkt_fwd") + pktfwd = check_process("mp_pkt_fwd") or check_process("poly_pkt_fwd") time.sleep(delay) @@ -135,7 +135,7 @@ def checkShutdown(): GPIO.output(gpio_grn, GPIO.LOW) time.sleep(.4) print "shutdown" - #os.system("sudo halt &") + os.system("sudo halt &") time.sleep(30) signal.signal(signal.SIGINT, signal_handler) diff --git a/monitor-ws2812.py b/monitor-ws2812.py index cb1eb48..d26fd20 100755 --- a/monitor-ws2812.py +++ b/monitor-ws2812.py @@ -96,7 +96,7 @@ def check_inet(delay): # Check WiFi AP mode and packet forwarder hostapd = check_process("hostapd") - pktfwd = check_process("mp_pkt_fwd") + pktfwd = check_process("mp_pkt_fwd") or check_process("poly_pkt_fwd") time.sleep(delay) @@ -142,7 +142,7 @@ def checkShutdown(): signal.signal(signal.SIGINT, signal_handler) # Create NeoPixel object 2 LEDs, 64 Brighness GRB leds -strip = Adafruit_NeoPixel(2, gpio_led, 800000, 5, False, 64, 0, ws.WS2811_STRIP_GRB) +strip = Adafruit_NeoPixel(2, gpio_led, 800000, 10, False, 64, 0, ws.WS2811_STRIP_GRB) # Intialize the library (must be called once before other functions). strip.begin() diff --git a/oled.py b/oled.py index 533c379..db82e3c 100755 --- a/oled.py +++ b/oled.py @@ -25,20 +25,102 @@ line4=line3+12 line5=line4+12 col1=0 +lora_rssi = None +lora_chan = None +lora_freq = None +lora_datr = None +lora_mote = None + +class LeaseEntry: + def __init__(self, leasetime, macAddress, ipAddress, name): + if (leasetime == '0'): + self.staticIP = True + else: + self.staticIP = False + self.leasetime = datetime.fromtimestamp(int(leasetime)).strftime('%Y-%m-%d %H:%M:%S') + self.macAddress = macAddress.upper() + self.ipAddress = ipAddress + self.name = name + + def serialize(self): + return { + 'staticIP': self.staticIP, + 'leasetime': self.leasetime, + 'macAddress': self.macAddress, + 'ipAddress': self.ipAddress, + 'name': self.name + } + class MyUDPHandler(SocketServer.BaseRequestHandler): + def is_json(self, myjson): + try: + json_object = json.loads(myjson) + except ValueError, e: + return False + return True + def handle(self): - global json_data + json_data + global lora_rssi + global lora_chan + global lora_freq + global lora_datr + global lora_mote + data = self.request[0] - #print(data) - #data = data[12::] - #print("\r\n") - print(data) - js_data = json.loads(data) + # for poly_pkt_fwd remove 12 first bytes + # if mp_pkt_fwd then packet are already fine + if data.find("{\"rxpk\":[") > 0: + data = data[12::] + + if self.is_json(data): + #print("\r\n") + #print(data) + js_data = json.loads(data) - if js_data.get('type')=='uplink': - json_data = data + # for mp_pkt_fwd + if js_data.get('type')=='uplink': + lora_mote = js_data["mote"] + lora_rssi = js_data["rssi"] + lora_chan = js_data["chan"] + lora_freq = js_data["freq"] + lora_datr = js_data["datr"] + # for poly_pkt_fwd + elif js_data.get('rxpk'): + lora_mote = "legacy_fwd" + lora_rssi = js_data["rxpk"][0]["rssi"] + lora_chan = js_data["rxpk"][0]["chan"] + lora_freq = js_data["rxpk"][0]["freq"] + lora_datr = js_data["rxpk"][0]["datr"] + +def leaseSort(arg): + # Fixed IPs first + if arg.staticIP == True: + return 0 + else: + return arg.name.lower() + +def getLeases(): + leases = list() + try: + with open("/var/lib/misc/dnsmasq.leases") as f: + for line in f: + elements = line.split() + if len(elements) == 5: + entry = LeaseEntry(elements[0],elements[1],elements[2],elements[3]) + leases.append(entry) + + leases.sort(key = leaseSort) + return [lease.serialize() for lease in leases] + + except Exception as e: + print "error in getLeases" + print(e) + print(type(e)) + return None + def do_nothing(obj): pass @@ -77,47 +159,121 @@ def bytes2human(n): return '%s%s' % (value, s) return "%sB" % n -def network(iface): - stat = psutil.net_io_counters(pernic=True)[iface] - return "Tx %s Rx %s" % (bytes2human(stat.bytes_sent), bytes2human(stat.bytes_recv)) +def if_stat(iface): + try: + stat = psutil.net_io_counters(pernic=True)[iface] + return "Tx %s Rx %s" % (bytes2human(stat.bytes_sent), bytes2human(stat.bytes_recv)) + + except KeyError as e: + return "Tx %s Rx %s" % (bytes2human(0), bytes2human(0)) + +def lan_info(iface): + ip = "No Interface" + stat = "" + try: + for snic in psutil.net_if_addrs()[iface]: + if snic.family == socket.AF_INET: + ip = snic.address + stat = if_stat(iface) + break + else: + ip ="No IP" + + return "%-5s: %s" % (iface, ip), stat -def lan_ip(iface): - for nic, addrs in psutil.net_if_addrs().items(): - if nic == iface: - for addr in addrs: - if addr.family==socket.AF_INET: - return "%-5s: %s" % (iface, addr.address) + except KeyError as e: + return ip, stat - return "%-5s: Unknown IP" % iface + +def uptime(): + try: + f = open( "/proc/uptime" ) + contents = f.read().split() + f.close() + except: + return "no /proc/uptime" + + total_seconds = float(contents[0]) + + # Helper vars: + MINUTE = 60 + HOUR = MINUTE * 60 + DAY = HOUR * 24 + + # Get the days, hours, etc: + days = int( total_seconds / DAY ) + hours = int( ( total_seconds % DAY ) / HOUR ) + minutes = int( ( total_seconds % HOUR ) / MINUTE ) + seconds = int( total_seconds % MINUTE ) + + # Build up the pretty string (like this: "N days, N hours, N minutes, N seconds") + string = "" + if days > 0: + string += str(days) + "d " + if len(string) > 0 or hours > 0: + string += str(hours) + "h " + if len(string) > 0 or minutes > 0: + string += str(minutes) + "m " + if hours == 0 and seconds >0: + string += str(seconds) + "s" + + return string; + +def ip_client(thislease): + ips = thislease["ipAddress"].split('.') + return "%s.%s: %s" % (ips[2],ips[3], thislease["name"]) def stats(): global looper + lease = None with canvas(device) as draw: #draw.rectangle((0,0,127,63), outline="white", fill="black") if looper==0: - if json_data!=None: - try: - o = json.loads(json_data) - draw.text((col1, line1),"Mote %s" % (o["mote"]), font=font10, fill=255) - draw.text((col1, line2),"RSSI %sdBi" % ( o["rssi"]), font=font10, fill=255) - draw.text((col1, line3),"Chan %s" % (o["chan"]), font=font10, fill=255) - draw.text((col1, line4),"Freq %.2f MHz" % (o["freq"]), font=font10, fill=255) - draw.text((col1, line5),"Rate %s" % (o["datr"]), font=font10, fill=255) - except: - draw.text((col1, line1),"Invalid JSON received", font=font10, fill=255) - pass + looper=1 + if lora_mote != None: + draw.text((col1, line1),"Mote %s" % lora_mote, font=font10, fill=255) + draw.text((col1, line2),"RSSI %sdBm" % lora_rssi, font=font10, fill=255) + draw.text((col1, line3),"Chan %s" % lora_chan, font=font10, fill=255) + draw.text((col1, line4),"Freq %.2f MHz" % lora_freq, font=font10, fill=255) + draw.text((col1, line5),"Rate %s" % lora_datr, font=font10, fill=255) else: draw.text((col1, line1),"No LoRaWAN Data yet", font=font10, fill=255) - looper=1 elif looper==1: + looper = 2 draw.text((col1, line1),"Host :%s" % socket.gethostname(), font=font10, fill=255) - draw.text((col1, line2), lan_ip("wlan0"), font=font10, fill=255) - draw.text((col1, line3), network("wlan0"), font=font10, fill=255) - #draw.text((col1, line4), lan_ip("uap0"), font=font10, fill=255) - #draw.text((col1, line5), network("uap0"), font=font10, fill=255) - looper=2 + # Try to get wlan0 if not then eth0 + ip, stats = lan_info("eth0") + if ip == "No Interface": + ip, stats = lan_info("wlan0") + + draw.text((col1, line2), ip, font=font10, fill=255) + draw.text((col1, line3), stats, font=font10, fill=255) + + ip, stats = lan_info("ap0") + if ip != "No IP" and ip != "No Interface": + draw.text((col1, line4), ip, font=font10, fill=255) + draw.text((col1, line5), stats, font=font10, fill=255) + lease = getLeases() + else: + draw.text((col1, line4), "ap0", font=font10, fill=255) + draw.text((col1, line5), "No Access Point", font=font10, fill=255) + + if lease == None: + looper = 3 elif looper==2: + looper = 3 + lease = getLeases() + lg = len(lease) + + draw.text((col1, line1), "Wifi Clients => %d" % lg, font=font10, fill=255) + if lg>=1: draw.text((col1, line2), ip_client(lease[0]), font=font10, fill=255) + if lg>=2: draw.text((col1, line3), ip_client(lease[1]), font=font10, fill=255) + if lg>=3: draw.text((col1, line4), ip_client(lease[2]), font=font10, fill=255) + if lg>=4: draw.text((col1, line5), ip_client(lease[3]), font=font10, fill=255) + + elif looper==3: + looper = 0 tempC = int(open('/sys/class/thermal/thermal_zone0/temp').read()) av1, av2, av3 = os.getloadavg() mem = psutil.virtual_memory() @@ -127,12 +283,13 @@ def stats(): draw.text((col1, line2), "MEM FREE: %s/%s" % (bytes2human(mem.available), bytes2human(mem.total)), font=font10, fill=255) draw.text((col1, line3), "DSK FREE: %s/%s" % (bytes2human(dsk.total-dsk.used), bytes2human(dsk.total)),font=font10, fill=255) draw.text((col1, line4), "CPU TEMP: %sc" % (str(tempC/1000)), font=font10, fill=255) - looper=3 + draw.text((col1, line5), "UP : %s" % uptime(), font=font10, fill=255) + else: - draw.text((col1, line1),"%s %s" % (platform.system(),platform.release()), font=font10, fill=255) - uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time()) - draw.text((col1, line2),str(datetime.now().strftime('%a %b %d %H:%M:%S')), font=font10, fill=255) - draw.text((col1, line3),"Uptime %s" % str(uptime).split('.')[0], font=font10, fill=255) + #draw.text((col1, line1),"%s %s" % (platform.system(),platform.release()), font=font10, fill=255) + #uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time()) + #draw.text((col1, line2),str(datetime.now().strftime('%a %b %d %H:%M:%S')), font=font10, fill=255) + #draw.text((col1, line3),"Uptime %s" % str(uptime).split('.')[0], font=font10, fill=255) looper=0 def main(): diff --git a/set_config.py b/set_config.py index 93469f0..8902bc7 100755 --- a/set_config.py +++ b/set_config.py @@ -92,7 +92,8 @@ if "router" in ttn_config: router = ttn_config['router'].get('mqtt_address', "mqtt://router.dev.thethings.network:1883") router = urlparse.urlparse(router) - router = router.hostname # mp_pkt_fwd only wants the hostname, not the protocol and port + #router = router.hostname # mp_pkt_fwd only wants the hostname, not the protocol and port + router = router.path # mp_pkt_fwd only wants the hostname, not the protocol and port else: router = "router.dev.thethings.network" diff --git a/setup.sh b/setup.sh deleted file mode 100755 index 02578e6..0000000 --- a/setup.sh +++ /dev/null @@ -1,94 +0,0 @@ -#! /bin/bash - -GW_DIR="/opt/loragw" - -echo "It's now time to create and configure your gateway on TTN" -echo "See https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector" -echo "once done, grab your gateway id (GW_ID) and key (GW_KEY) and paste them here" - -if [[ $GW_ID == "" ]]; then - echo "No environement for GW_ID" - echo "" - echo -n "Please enter GW_ID: " - read GW_ID - export GW_ID -fi - -if [[ $GW_KEY == "" ]]; then - echo "No environement for GW_KEY" - echo "See https://www.thethingsnetwork.org/docs/gateways/registration.html#via-gateway-connector" - echo "" - echo -n "Please enter GW_KEY: " - read GW_KEY - export GW_KEY -fi - -if [[ $GW_RESET_PIN == "" ]]; then - GW_RESET_PIN=25 - echo "No environement for GW_RESET_PIN" - echo "Please select your reset pin" - echo "see https://github.com/jpmeijers/ttn-resin-gateway-rpi/blob/master/README.md" - echo "under section Reset Pin Values" - echo "enter 25 (GPIO25) for this RAK831 shield or classic Gonzalo Casas" - echo "enter 17 (GPIO17) for classic ic880A by CH2i" - echo "" - echo -n "Please enter GW_RESET_PIN [$GW_RESET_PIN]:" - read GW_RESET_PIN - export GW_RESET_PIN -fi - -# Set the reset în in startup shell -sudo sed -i -- "s/RESET_BCM_PIN=25/RESET_BCM_PIN=$GW_RESET_PIN/g" ./start.sh - -# script to get config from TTN server -python set_config.py - -# Copy config to running folder -sudo mv global_conf.json $GW_DIR/ -sudo cp start.sh $GW_DIR/ - -# Prepare start forwarder as systemd script -sudo cp ./loragw.service /lib/systemd/system/ -sudo systemctl enable loragw.service -sudo systemctl start loragw.service - -# ask if we need to enable monitoring service -sudo cp ./oled.py $GW_DIR/ -sudo cp ./monitor-ws2812.py $GW_DIR/ -sudo cp ./monitor-gpio.py $GW_DIR/ -sudo ln -s $GW_DIR/monitor-ws2812.py $GW_DIR/monitor.py -sudo cp ./monitor.service /lib/systemd/system/ -sudo cp ./oled.service /lib/systemd/system/ - -echo "" -echo "You can enable monitor service that manage blinking led to" -echo "display status and also add button management to shutdown PI" -echo -n "Would you like to enable this [y/N]:" -read rep - -if [[ "$rep" == "y" ]]; then - sudo systemctl enable monitor.service - sudo systemctl start monitor.service - echo "monitor service enabled!" -fi - -echo "" -echo "You can enable OLED display service to show informations" -echo -n "Would you like to enable this [y/N]:" -read rep - -if [[ "$rep" == "y" ]]; then - sudo systemctl enable oled.service - sudo systemctl start oled.service - echo "Oled service enabled!" - echo "Please follow the procedure located here to finish setup" - echo "https://github.com/ch2i/LoraGW-Setup/blob/master/doc/DisplayOled.md" - echo "Also don't forget to set the OLED wiring and type by editing file" - echo "/opt/loragw/oled.py (as described into procedure)" -fi - -echo "" -echo "all done, please check service running log with" -echo "sudo journalctl -f -u loragw.service" - - diff --git a/start.sh b/start.sh index 5239c67..9b6e3be 100755 --- a/start.sh +++ b/start.sh @@ -1,5 +1,11 @@ #! /bin/bash +# Test the connection, wait if needed. +#while [[ $(ping -c1 google.com 2>&1 | grep " 0% packet loss") == "" ]]; do +# echo "[Lora Gateway]: Waiting for internet connection..." +# sleep 2 +# done + # Reset RAK831 PIN SX1301_RESET_BCM_PIN=25 @@ -10,15 +16,21 @@ WAIT_GPIO() { # cleanup GPIO if [ -d /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN ] then - echo "$SX1301_RESET_BCM_PIN" > /sys/class/gpio/unexport; WAIT_GPIO + echo "GPIO$SX1301_RESET_BCM_PIN Already available" +else + echo "$SX1301_RESET_BCM_PIN" > /sys/class/gpio/export; WAIT_GPIO fi # setup GPIO -echo "$SX1301_RESET_BCM_PIN" > /sys/class/gpio/export; WAIT_GPIO -echo "out" > /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN/direction; WAIT_GPIO -echo "1" > /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN/value; WAIT_GPIO -echo "0" > /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN/value; WAIT_GPIO -echo "in" > /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN/direction; WAIT_GPIO +echo "out" > /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN/direction +WAIT_GPIO +echo "1" > /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN/value +WAIT_GPIO +echo "0" > /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN/value +WAIT_GPIO + +# removed, prevent start on IMST Gateway Lite +#echo "in" > /sys/class/gpio/gpio$SX1301_RESET_BCM_PIN/direction # Fire up the forwarder. ./mp_pkt_fwd diff --git a/wificfg.json b/wificfg.json new file mode 100644 index 0000000..0c07bd4 --- /dev/null +++ b/wificfg.json @@ -0,0 +1,16 @@ +{ + "dnsmasq_cfg": { + "address": "/#/192.168.50.1", + "dhcp_range": "192.168.50.50,192.168.50.100,1h", + "vendor_class": "set:device,IoT" + }, + "host_apd_cfg": { + "ip": "192.168.50.1", + "ssid": "_AP_SSID_", + "wpa_passphrase":"_AP_PASSWORD_", + "channel": "6" + }, + "wpa_supplicant_cfg": { + "cfg_file": "/etc/wpa_supplicant/wpa_supplicant.conf" + } +}