You need to manually reapply some settings in Cisco DNAC after the upgrade.

Currently I noticed two issues after upgrading DNAC in all previous version including the latest (currently on 2.3.5.5):

– Backups stop working. Solution is to reapply settings. It’s enough to modify one letter in Server Path in NFS tab and click Apply:

– DNAC can’t reach ISE PAN server (ISE PAN ERS reachability failed for ISE server). Solution is to reapply ISE server connections, just enter the password again and apply it. Settings are located in System Settings, Authentication and Policy servers:

I recently experienced an issue with my Hikvision doorvilla DS-KV8113-WME1(B), which was connected to my network via WiFi. On occasion, especially following a power outage, the device would lose its WiFi settings. This required me to disassemble the unit, connect it via a UTP cable, and reconfigure the settings—a frustrating and time-consuming process. Due to this, I wouldn’t recommend this particular Hikvision model.

To resolve this, I decided to implement a workaround by using the smallest WiFi access point (AP) I could find, placing it in the wall cavity behind the Hikvision unit, and connecting the device to this AP via a UTP cable. Essentially, I created a WiFi-to-Ethernet bridge. The AP I chose for this task was the Mikrotik RBcAPL-2nD.

However, connecting a Mikrotik device to a non-Mikrotik device in a pseudobridge setup has certain limitations, as detailed in their official documentation: Mikrotik Wireless Station Modes.

Despite these limitations, I managed to get it functioning with my PfSense system, but with a few caveats:

  • The client device (in this case, the Hikvision unit) must be assigned a static IP, as DHCP does not function over a pseudobridge.
  • The client’s IP address must belong to the same subnet that the WiFi AP is connected to.
  • It’s necessary to disable the spanning-tree protocol in the Mikrotik settings. Be sure to apply all your configurations beforehand, as you will lose access to the Mikrotik management interface after this change.
  • Here’s a brief guide on what you need to do:

  • Set up a WiFi profile on your Mikrotik device to connect to your existing WiFi network.
  • Change the station mode to pseudobridge.
  • Disable the DHCP server.
  • Turn off the spanning-tree protocol.
  • Below is the complete configuration. Replace “YOUR-WIFI-SSID” and “YOUR-WIFI-PASS” with your network’s details.

    # oct/19/2023 17:21:59 by RouterOS 6.48.7
    # software id = M2DK-HSWA
    #
    # model = RBcAPL-2nD
    # serial number = HET091AHV58
    /interface bridge
    add comment=defconf name=bridge
    /interface list
    add comment=defconf name=WAN
    add comment=defconf name=LAN
    /interface wireless security-profiles
    set [ find default=yes ] supplicant-identity=MikroTik
    add authentication-types=wpa-psk,wpa2-psk mode=dynamic-keys name=YOUR-WIFI-SSID \
        supplicant-identity=MikroTik wpa-pre-shared-key=YOUR-WIFI-PASS \
        wpa2-pre-shared-key=YOUR-WIFI-PASS
    /interface wireless
    set [ find default-name=wlan1 ] band=2ghz-g/n channel-width=20/40mhz-XX \
        country=slovenia disabled=no distance=indoors frequency=auto \
        installation=indoor mode=station-pseudobridge security-profile=YOUR-WIFI-SSID \
        ssid=YOUR-WIFI-SSID wireless-protocol=802.11
    /ip hotspot profile
    set [ find default=yes ] html-directory=hotspot
    /ip pool
    add name=default-dhcp ranges=192.168.88.10-192.168.88.254
    /ip dhcp-server
    add address-pool=default-dhcp interface=bridge name=defconf
    /interface bridge port
    add bridge=bridge comment=defconf interface=wlan1 multicast-router=disabled \
        trusted=yes
    add bridge=bridge interface=ether1 multicast-router=disabled trusted=yes
    add bridge=bridge disabled=yes interface=all
    /ip neighbor discovery-settings
    set discover-interface-list=LAN
    /interface list member
    add comment=defconf interface=bridge list=LAN
    add comment=defconf interface=ether1 list=WAN
    /ip address
    add address=192.168.88.1/24 comment=defconf disabled=yes interface=bridge \
        network=192.168.88.0
    /ip dhcp-client
    # DHCP client can not run on slave interface!
    add comment=defconf disabled=no interface=ether1
    add disabled=no interface=bridge
    /ip dhcp-server network
    add address=192.168.88.0/24 comment=defconf gateway=192.168.88.1
    /ip dns
    set allow-remote-requests=yes
    /ip dns static
    add address=192.168.88.1 comment=defconf name=router.lan
    /ip firewall filter
    add action=accept chain=input comment=\
        "defconf: accept established,related,untracked" connection-state=\
        established,related,untracked
    add action=drop chain=input comment="defconf: drop invalid" connection-state=\
        invalid
    add action=accept chain=input comment="defconf: accept ICMP" protocol=icmp
    add action=accept chain=input comment=\
        "defconf: accept to local loopback (for CAPsMAN)" dst-address=127.0.0.1
    add action=drop chain=input comment="defconf: drop all not coming from LAN" \
        in-interface-list=!LAN
    add action=accept chain=forward comment="defconf: accept in ipsec policy" \
        ipsec-policy=in,ipsec
    add action=accept chain=forward comment="defconf: accept out ipsec policy" \
        ipsec-policy=out,ipsec
    add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \
        connection-state=established,related
    add action=accept chain=forward comment=\
        "defconf: accept established,related, untracked" connection-state=\
        established,related,untracked
    add action=drop chain=forward comment="defconf: drop invalid" \
        connection-state=invalid
    add action=drop chain=forward comment=\
        "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \
        connection-state=new in-interface-list=WAN
    /ip firewall nat
    add action=masquerade chain=srcnat comment="defconf: masquerade" \
        ipsec-policy=out,none out-interface-list=WAN
    /ip service
    set telnet disabled=yes
    set ftp disabled=yes
    set www-ssl disabled=no
    set api disabled=yes
    set api-ssl disabled=yes
    /system clock
    set time-zone-name=Europe/Ljubljana
    /system identity
    set name=RouterOS
    /tool mac-server
    set allowed-interface-list=LAN
    /tool mac-server mac-winbox
    set allowed-interface-list=LAN
    

    Install npm, Puppeteer and dependencies:

    apt update -y && apt upgrade -y
    apt install -y npm
    apt install -y libx11-xcb1 libxcomposite1 libxcursor1 libxdamage1 libxi-dev libxtst-dev libnss3 libcups2 libxss1 libxrandr2 libasound2 libatk1.0-0 libatk-bridge2.0-0 libpangocairo-1.0-0 libgtk-3-0 libgbm1
    npm install -g n
    n lts
    hash -r
    npm install puppeteer
    

    Install Chrome without snap:

    wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
    apt install ./google-chrome-stable_current_amd64.deb
    

    Make a test file test.js:

    const puppeteer = require('puppeteer');
    const fs = require('fs');
    
    async function run () {
      const browser = await puppeteer.launch({
        executablePath: '/usr/bin/google-chrome-stable',
        args: ['--no-sandbox'],
        defaultViewport: {width: 1920, height: 1080}
      });
      const page = await browser.newPage();
      await page.goto('https://www.google.com');
      await sleep(3000);
    
      await page.screenshot({path: 'screenshot.png'});
      const html = await page.content();
      fs.writeFileSync('source.htm', html);
    
      browser.close();
    }
    run();
    
    function sleep(ms) {
      return new Promise((resolve) => {
        setTimeout(resolve, ms);
      });
    } 
    

    Test it:

    node test.js
    

    1. Update system and optionally disable X Desktop, we don’t need GUI

    apt-get update
    apt-get upgrade
    raspi-config

    Select menu: 3, B1, B1

    2. Install dependencies

    apt-get install subversion libsigc++-2.0-dev g++ make libsigc++-1.2-dev libgsm1-dev screen \
    libpopt-dev tcl8.5-dev libgcrypt-dev libspeex-dev libasound2-dev alsa-utils install qt-sdk git groff -y

    3. Add a new user

    adduser svxlink

    4. Download svxlink source

    cd /usr/src; wget https://github.com/sm0svx/svxlink/archive/15.11.tar.gz; tar xvf 15.11.tar.gz; cd svxlink-15.11/src; mkdir build; cd build

    5. Compile and install svxlink

    cmake -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc \
            -DLOCAL_STATE_DIR=/var ..
    make
    make doc
    make install
    ldconfig
    

    6. Install sounds

    cd /usr/share/svxlink/sounds; wget https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2
    tar xvf svxlink-sounds-en_US-heather-16k-13.12.tar.bz2
    mv en_US-heather-16k en_US; rm -rf svxlink-sounds-en_US-heather-16k-13.12.tar.bz2

    7. Configure sound levels

    alsamixer

    Press F6 and select usb soundcard.
    Press F5 to show all.
    Increase gain on CAPTURE, around 80 is fine, experiment otherwise.
    Exit alsamixer and save the settings with:

    alsactl store

    8. Tweak configuration files in /etc/svxlink/svxlink.conf and /etc/svxlink/svxlink.d/ModuleEchoLink.conf

    svxlink.conf: I will show you only modified lines

    Uncomment LOCATION_INFO=locationInfo to show your Echolink on aprs.fi map.
    MODULES=ModuleEcholink
    CALLSIGN=Yoursign-L
    SHORT_IDENT_INTERVAL=0
    LONG_IDENT_INTERVAL=0

    Under [Rx1]

    AUDIO_DEV=alsa:plughw:1 #Hardware ID of the soundcard, usually 1 on rpi with usb soundcard
    SQL_START_DELAY=100 #Prevent TX, RX loop
    VOX_THRESH=500 #Increase if your VOX gets falsly opened

    Under [Tx1]:

    AUDIO_DEV=alsa:plughw:1
    PTT_TYPE=SerialPin
    PTT_PORT=/dev/ttyUSB0 #Depends what you have for PTT triggering, I do it with RS232 to USB converter

    Under [LocationInfo]
    #This is mostly self explanatory

    APRS_SERVER_LIST=poland.aprs2.net:14580
    STATUS_SERVER_LIST=aprs.echolink.org:5199
    #Go to maps.google.com, select your location, right click, what's here
    #and you'll get coordinates, for example: 45.660325, 14.291537 Go to https://rechneronline.de/winkel/degrees-minutes-seconds.php
    #and convert from decimal degrees provided from maps.google.com to degrees, arc minutes, arc seconds.
    #Enter converted
    #coordinates.
    
    LON_POSITION=14.17.29E
    LAT_POSITION=45.39.37N
    CALLSIGN=EL-yourcallsign
    FREQUENCY=145.275
    TX_POWER=5
    ANTENNA_GAIN=0
    ANTENNA_HEIGHT=5m
    ANTENNA_DIR=-1
    PATH=WIDE1-1
    BEACON_INTERVAL=10
    TONE=123
    COMMENT=SvxLink by SM0SVX (svxlink.sourceforge.net)

    ModuleEcholink.conf:

    ALLOW_IP=192.168.0.0/24 #Depends on your home network setup,
    #it could be also ALLOW_IP=192.168.1.0/24
    SERVERS=europe.echolink.org
    CALLSIGN=yoursign-L
    PASSWORD=your echolink password
    SYSOPNAME=yourname
    LOCATION=[Svx] comment about your echolink
    LINK_IDLE_TIMEOUT=0
    AUTOCON_ECHOLINK_ID=ID of the remote repeater for example AUTOCON_ECHOLINK_ID=609569
    AUTOCON_TIME=1200
    DESCRIPTION=edit text to fit your needs
    reboot

    9. Run svxlink

    svxlink

    Try to transmit, usb soundcards on rpi are tricky. You will probably get a warning:
    Rx1: Distorsion detected! Please lower the input volume!
    Don’t worry about it.
    Exit and run svxlink as daemon

    svxlink --daemon

    10. Start svxlink at boot
    You need to wait some time after boot for Pi to initialize devices.
    It will not work when you start svxlink immediately after the boot,
    the process will run but there will be no access to PTT. Open
    /etc/rc.local and add this two lines at the end of the file, before exit 0

    sleep 120
    /bin/bash -c '/usr/bin/svxlink --pidfile=/var/run/svxlink.pid --daemon'
    

    This will start svxlink 2 minutes after boot.

    #!/bin/sh
    
    # Get APRS weather data from aprs.fi
    
    wxstation="S55MA-10"
    
    # Basic weather data
    temp="$(wget -q https://aprs.fi/weather/a/${wxstation} -O - | grep Temperature | egrep '[-+]?([0-9]*\.[0-9]+|[0-9]+)' -o)"
    humidity="$(wget -q https://aprs.fi/weather/a/${wxstation} -O - | grep Humidity | egrep '[-+]?([0-9]*\.[0-9]+|[0-9]+)' -o)"
    wind="$(wget -q https://aprs.fi/weather/a/${wxstation} -O - | grep Wind | egrep '[-+]?([0-9]*\.[0-9]+|[0-9]+)' -o | sed -n -e 2p)"
    rain="$(wget -q https://aprs.fi/weather/a/${wxstation} -O - | grep Rain | egrep '[-+]?([0-9]*\.[0-9]+|[0-9]+)' -o | sed -n -e 1p)"
    
    # Telemetry
    radioactivity="$(wget -q https://aprs.fi/telemetry/a/${wxstation} -O - | grep Radioactivity | egrep '[-+]?([0-9]*\.[0-9]+|[0-9]+)' -o | sed -n -e 5p)"
    
    printf "%s\n" "Temperature: ${temp}°C" "Humidity: ${humidity}%" "Wind: ${wind} m/s" "Rain: ${rain} mm/h" "Radioactivity: ${radioactivity} uSv/h"
    

    Enable server ports on Xastir. We need to use the command line binary xastir_udp_client which is part of Xastir. To send the data over RF, you need to have Xastir configured with your transmitter already.

    More info about the mail APRS service: http://www.aprs-is.net/email.aspx

    The basic string is:

    xastir_udp_client XastirIP port callsing passcode -to_rf 'callsign>APRS::EMAIL    :EmailOfReceiver@something.com message'

    Real example:

    xastir_udp_client 192.168.0.140 2023 S55MA-10 22222 -to_rf 'S55MA-10>APRS::EMAIL    :s55ma@radioamater.si hello'

    Note: You may only send one line messages of 64 total characters maximum for the message even though the documentation is saying 67. You have to put 4 white spaces between EMAIL and EmailOfReceiver, so the total lenght of EMAIL+white spaces is 9 characters.

    This post is about Xastir, but on the side note, most APRS capable handhelds stations are not able of sending email messages through APRS. One portable station that’s able to do it is Kenwood TH-D72. I found this post about it. Too bad other portables are not able to do that where this feature is the most usefull, I mean, it’s not like I’m going to need aprs to email service from my home station, I’d likely need it outdoors for emergency situations or to send an email when I’m abroad and without cellular data service.

    Quick script for sending messages:

    #!/bin/bash
    
    #APRS to Email script using Xastir
    #Define variables
    #Xastir server and port
    server=192.168.0.140
    port=2023
    
    #Authentication info
    user=S55MA
    passcode=22222
    
    echo "Enter sender (yours or some others callsign)"
    read sender
    sendercapital="$(echo $sender | awk '{print toupper($0)}')"
    
    echo "Enter destination email:"
    read email
    
    echo "Enter your message (max 64 characters):"
    read message
    
    #Count message characters
    msglenght="$(echo $message | wc -c)"
    
    #Restart script if message exceeds 64 characters.
    if [ "$msglenght" -gt 64 ]; then
    echo "Your message exceeded 64 characters, try again!"
    exec bash "$0"
    else
    xastir_udp_client $server $port $user $passcode -to_rf "$sendercapital>APRS::EMAIL    :$email $message" >/dev/null 2>&1
    echo "Message has been sent."
    fi
    

    In my previous post I wrote about sending objects and telemetry via command line to APRS-IS server.

    You can also do that with Xastir, but as a bonus point, you can do it all via RF if your Xastir setup is already paired to the radio and configured to transmit. You can use the scripts from my previous blog post, you only need to change some commands.

    Xastir GUI is lacking options to send multiple different beacons or telemetry data. There is a binary called xastir_udp_client that comes with normal Xastir setup which takes care of that, but you need to run it from a command line and do some custom scripting. To use this feature, you need to enable server ports. Open xastir, go to interface menu and click enable server ports.

    The basic commands to create an object with a house icon are:

    Send via RF:

    xastir_udp_client XastirIP port user passcode -to_rf 'senduser>APN100,WIDEPATH*:=latitude/longtitude-Comment'
    xastir_udp_client 192.168.0.140 2023 S55MA-10 22558 -to_rf 'S55MA-10>APN100,WIDE2-1*:=4539.94N/01417.67E-QTH'

    Send via Internet only (remove -to_rf):

    xastir_udp_client XastirIP port user passcode 'senduser>APN100,TCPIP*:=latitude/longtitude-Comment'
    xastir_udp_client 192.168.0.140 2023 S55MA-10 22558 'S55MA-10>APN100,TCPIP*:=4539.94N/01417.67E-QTH'

    Why did I write “senduser” in string? Because you can place remote objects on the map that’s not your own call sign – sticking to the protocol rules, you need to change the code to show the correct path if you want to place objects with not your own sign. The only drawback with Xastir in this example is, it overrides your permanent timestamp (111111z). More info about sending objects with not your sign is in my previous post. Why is it so “cool” to collect and send data from another stations to RF? Let’s say you want to transmit critical data to offline users like repeater offset or echolink node number. You can also transmit weather data from other non RF stations to RF. So for example if I’m walking in the forest with my handheld APRS capable station I can receive weather or repeater data directly on my handheld without having the internet.

    Example:

    I’m collecting data from this weather station: https://www.hobolink.com/p/d0a7b4f0dbc44b973b0a5cce75a0521d and sending it to RF, including telemetry.

    https://aprs.fi/weather/S51Y

    Another example is sending repeater and echolink data to RF:

    You see that purple lines? That means the object was put on the map via my station (S55MA-10).

    You can also see the path at the bottom of a white rectangle “[APN101 via WIDE2-1,qAR,S55MA-10]”

    Note that this is actually faking an object, it looks like the transmitter is at the object and it’s

    being igated by my station, but it’s actually my station doing the transmissions. This is a good example  how to not

    stick to the protocol rules 😉 I was unable to do it with xastir_udp_client binary, it rewrites it’s path if you want to send another

    object. There is also a “bug” or a feature, I’m not sure yet, that xastir_udp_client inserts additional } in the string. I don’t know

    why is that, but it’s unwanted.

    If you want to show that remote object is put on the map by your station, you need to change the path as I mentioned above,

    stick to the protocol, but I don’t think that’s possible with xastir_udp_client. I neglected this and I’m going to update my scripts

    if I find the correct solution.

    Example script I’m using to send Echolink data to RF:

    #!/bin/bash
    
    #Transmit objects via Xastir to RF.
    
    #Define login info
    user=S55MA-10
    password=23458
    
    #Define object user info
    usersend=S55UPO-10
    
    #Define xastir server
    server=192.168.0.140
    port=2023
    
    #Define station location (Echolink Postojna, Pecna Reber)
    lat=4546.72N
    lon=01413.80E
    
    #Define data
    comment="Echolink Postojna 438.825Mhz -7.6M T123 Node:609569"
    data="$usersend>APN101,WIDE2-1:=${lat}E${lon}0${comment}"
    
    #Send object to RF
    /usr/bin/xastir_udp_client $server $port $user $password -to_rf "$data"
    
    #Debugging
    #printf "$data\n"
    

    Example of my hobolink weather collector script. Hobolink to APRS. It’s similar to the script in my previous post so I won’t go into details.

    #!/bin/bash
    
    #Read data from HOBOlink station and send it to APRS network via Xastir. Server ports option has to be enabled on Xastir.
    
    #Create a temporary RAM disk (we don't want to write on a SD card too often).
    #You need to run this script as sudo (root) or create a temporary ramdisk at boot as root
    #and run this script as a normal user.
    if [ ! -d "/mnt/ramdisk/" ]; then
    mkdir -p /mnt/ramdisk; mount -t tmpfs tmpfs /mnt/ramdisk -o size=10m
    fi
    
    #Check if file exist
    if [ ! -f "/mnt/ramdisk/sequence_numberjavornik.txt" ]; then
    touch /mnt/ramdisk/sequence_numberjavornik.txt
    fi
    
    #Read sequence number
    read num < /mnt/ramdisk/sequence_numberjavornik.txt
    num=$((num + 1))
    if (( num == 1000 )); then
    num=0
    fi
    
    #Error log file
    error=/var/log/wxdata.log
    
    #Define login info
    user=S55MA-10
    password=passcode
    
    #Insert the same as user. Insert other user sign if you want to put another station not owned by you on the map. Be aware that telemetry
    #requires 9 char long callsign so you need to add whitespaces after the callsign and telemetry, for example:
    #t2="$usersend>APN002,WIDE2-1::"$usersend" :PARM.Solar Radiation,Battery" #5 whitespaces between "$usersend" and :PARM because
    #S51Y is only 4 char long.
    usersend=S51Y
    
    #Define xastir server
    server=192.168.0.140
    port=2023
    
    #Define station location (Veliki Javornik, Postojna)
    lat=4545.48N
    lon=01417.72E_ #_ is a symbol for WX station
    
    #Download weather data
    file=/mnt/ramdisk/wxdata.txt
    file1=/mnt/ramdisk/wxdata1.txt
    curl -s https://www.hobolink.com/p/d0a7b4f0dbc44b973b0a5cce75a0521d | grep nobr | awk -F\> '{print $6}' | sed 's/<\/nobr//g' > "$file"
    curl -s https://www.hobolink.com/p/d0a7b4f0dbc44b973b0a5cce75a0521d | grep "Wind Direction" -A 1 | grep "latest-conditions-info-reading" | awk -F\> '{print $5}' | awk '{print $2}' | grep -o '[0-9]\+' > "$file1"
    
    if [ -s "$file" ] #If downloaded file is not empty, continue, else quit
    then
    
    #Date in UTC
    zuludate="$(date -u +%d%H%M)"
    
    #APRS needs temperature in F, data is fetched in degress C so we need to convert it.
    tempC="$(sed -n -e 1p "$file")"
    tempF="$(echo "((9/5) * $tempC) + 32" | bc -l | awk -F. '{print $1}')"
    
    #Relative humidity
    rh="$(sed -n -e 2p "$file" | awk -F. '{print $1}')"
    
    #APRS need windspeed in mph, data is fetched in meters per second so we need to convert it.
    windspeedms="$(sed -n -e 4p "$file")"
    windspeedmph="$(echo "(($windspeedms * 3.6) / 1.609344)" | bc -l | awk -F. '{print $1}')"
    gustsms="$(sed -n -e 5p "$file")"
    gustsmph="$(echo "(($gustsms * 3.6) / 1.609344)" | bc -l | awk -F. '{print $1}')"
    
    rain1h="$(sed -n -e 7p "$file" | awk -F. '{print $1}')"
    winddirection="$(cat "$file1")"
    solarradiation="$(sed -n -e 6p "$file")" #For telemetry only
    batteryvoltage="$(sed -n -e 8p "$file" | tr -d '.' | head -c 3)" #For telemetry only
    
    #Station comment
    aprscomment="Veliki Javornik 1268m asl"
    
    #Xastir weather variable with padding zeros for correct APRS format
    printf -v xastirwx "%03d/%03dg%03dt%03dr%03dh%02d%s" "$winddirection" "$windspeedmph" "$gustsmph" "$tempF" "$rain1h" "$rh" "$aprscomment"
    
    #Xastir user and WIDE path data
    xastirpath="$usersend>APN100,WIDE2-1:=$lat/$lon"
    
    #Telemetry
    printf -v t1 "%s>APN002,WIDE2-1:T#%03d,%03d,%03d,000,000,000,00000000" "$usersend" "$num" "$solarradiation" "$batteryvoltage"
    t2="$usersend>APN002,WIDE2-1::$usersend :PARM.Solar Radiation,Battery"
    t3="$usersend>APN002,WIDE2-1::$usersend :UNIT.W/m2,Volts"
    
    #Add coefficient in EQNS field to convert real data.
    t4="$usersend>APN002,WIDE2-1::$usersend :EQNS.0,1,0,0,0.01,0,0,0,0,0,0.0,0,0,0,0"
    t5="$usersend>APN002,WIDE2-1::$usersend :BITS.00000000,Weather station Veliki Javornik Postojna"
    
    #Send data to Xastir
    /usr/bin/xastir_udp_client $server $port $user $password -to_rf "$xastirpath$xastirwx"
    
    #Send telemetry data to Xastir
    #Send PARAMS, UNITS, EQNS and BITS every 2 hours.
    #Check if file exist
    if [ ! -f "/mnt/ramdisk/datejavornik.txt" ]; then
    echo 0 > /mnt/ramdisk/datejavornik.txt
    fi
    
    #calculate time difference
    read olddate < /mnt/ramdisk/datejavornik.txt
    date="$(date +%s)"
    diff="$(echo "$date - $olddate" | bc)"
    
    if [ "$diff" -gt 7200 ]; then
    /usr/bin/xastir_udp_client $server $port $user $password -to_rf "$t1"
    /usr/bin/xastir_udp_client $server $port $user $password -to_rf "$t2"
    /usr/bin/xastir_udp_client $server $port $user $password -to_rf "$t3"
    /usr/bin/xastir_udp_client $server $port $user $password -to_rf "$t4"
    /usr/bin/xastir_udp_client $server $port $user $password -to_rf "$t5"
    echo "$date" > /mnt/ramdisk/datejavornik.txt
    else
    /usr/bin/xastir_udp_client $server $port $user $password -to_rf "$t1"
    fi
    
    #Delete old data
    rm -f /mnt/ramdisk/wxdata.txt /mnt/ramdisk/wxdata1.txt
    
    #Write sequence number
    echo "$num" > /mnt/ramdisk/sequence_numberjavornik.txt
    
    else
    echo ["$(date -u)"] Error downloading data >> "$error"
    fi
    

    Link to the Hobolink to APRS script: https://pastebin.com/v6cQkm54

    This is to internet only, not to RF. You need TNC software and a radio station to send it via RF.

    We need ncat which is a part of nmap and bc.

    sudo apt-get install nmap bc
    

    First, some usefull tools:
    APRS coordinate converter: http://digined.pe1mew.nl/?How_to:Convert_coordinates
    APRS passcode generator: http://apps.magicbug.co.uk/passcode/

    There are more APRS IS servers available to connect to, I decided to use poland.aprs2.net, the generic one is rotate.aprs.net.
    Default port is 14580.

    The protocol goes like this (more info http://www.aprs-is.net/Connecting.aspx):
    – Authenticate with APRS-IS server
    – Send data

    So the data you are sending is:
    – user yourHAMSIGN pass passcode
    – objectdata

    Bash one line command to send data:

    printf "%s\n" "user yourHAMSIGN pass passcode" "yourHAMSIGN>APN100,TCPIP*:=latitude/longtitude-comment" | ncat poland.aprs2.net 14580

    Example:

    printf "%s\n" "user S55MA-13 pass 23558" "S55MA-13>APN100,TCPIP*:=4246.29N/01412.79E_247-QTH" | ncat poland.aprs2.net 14580

    This should place S55MA-13 on a map with a house icon.
    Look into aprs.fi raw data for your ham sign (https://aprs.fi/?c=raw&call=yourHAMSIGN) to find any formatting errors. It should look like this:

    2017-07-27 16:18:32 CEST: S55MA-13>APN100,TCPIP*,qAC,T2POLAND:=4246.29N/01412.79E_247-QTH

    Important: With this commands you can place (fake) or “steal” an objects that are not your own stations by placing another station sign in the second yourHAMSIGN field. This will work, but it will look like the object is coming via another station, igated by your station. That’s ok, the object will be placed correctly on the map, but for the sake of following correct protocol procedures, you need to change a string a little bit so the other station object will show correct path of where it’s coming from.

    When placing another object (not your own) on the map, you need to add the timestamp to the string. If the object is permanent, timestamp should be “111111z” (http://www.aprs.org/info/object-perm.txt)

    Example:

    printf "%s\n" "user yourHAMSIGN pass passcode" "yourHAMSIGN>APN100,TCPIP*:;ANOTHERSTATION_CALLSIGN *111111zlatitude/longtitude-comment" | ncat poland.aprs2.net 14580
    printf "%s\n" "user S55MA-10 pass 22358" "S55MA-10>APN100,WIDE2-1*:;S55MA-14 *111111z4139.94N/01217.67E-test" | ncat --send-only poland.aprs2.net 14580

    Note: ANOTHERSTATION_CALLSIGN is by protocol defined as 9 characters long and you need to add whitespaces between ANOTHERSTATION_CALLSIGN and *111111z
    Example: S51Y has four characters only so you need to add 5 whitespaces between ANOTHERSTATION_CALLSIGN and *111111z
    The string would look like:

    printf "%s\n" "user S55MA-10 pass 22358" "S55MA-10>APN100,WIDE2-1*:;S51Y     *111111z4139.94N/01217.67E-test" | ncat --send-only poland.aprs2.net 14580

    If you don’t want to use one line command, you can create a simple script (for placing your own station):

    #!/bin/bash
    
    #Define login info
    user=yourHAMSIGN
    password=passcode
    
    #Define object user info
    senduser=yourHAMSIGN
    
    #Define APRS-IS server
    server=poland.aprs2.net
    port=14580
    
    #Define station location
    lat=4146.72N
    lon=01213.80E
    
    #Define data
    comment="QTH"
    data="$senduser>APN100,TCPIP*:=${lat}/${lon}-${comment}"
    
    #Send data to the server
    printf "%s\n" "user $user pass $password" "${senduser}>APN100,TCPIP*:=${lat}/${lon}-${comment}" | ncat poland.aprs2.net 14580
    

    NOTE: Don’t send data to often. For objects it’s sufficient to send it every few hours. Don’t spam the network.

    You can send telemetry the same way but it’s a little bit trickier because APRS protocol has coeficients for displaying the correct values.
    For example let’s say we’ll read a raspberryPI CPU temperature and send it to APRS-IS network.

    #!/bin/bash
    #Define login info
    user=yourHAMSIGN
    password=passcode
    
    #Define object user info
    senduser=yourHAMSIGN
    
    #Define APRS-IS server
    server=poland.aprs2.net
    port=14580
    
    #Define station location
    lat=4146.72N
    lon=01213.80E
    
    #Define data
    comment="QTH"
    data="$senduser>APN100,TCPIP*:=${lat}/${lon}-${comment}"
    
    #Authentication variable
    aprsauth="user $user pass $password"
    
    #Read raspberry-pi CPU temperature
    tempraw=/opt/vc/bin/vcgencmd measure_temp #Read pi temperature
    
    #Filter result to numbers only 
    tempfloat="$(echo "$tempraw" | awk -F= '{print $2}' | awk -F\' '{print $1}')"
    
    #Aprs telemetry protocol accepts 3 whole (int) 
    #numbers only so we need
    #to convert the result (tempfloat) into 3 whole 
    #numbers. So if tempraw=40.3, it will
    #convert it to 403. If tempraw=8.5, it will convert 
    #it to 85 and we'll add the leading zero
    #to create 3 number format 085 later bellow.
    temp="$(echo "$tempfloat * 10" | bc | awk -F. '{print $1}')"
    
    #Project comment
    projectcomment=Rpi temperature
    
    #Generate telemetry strings
    #Read data and put it into variable
    #%s means string
    #%03d means prepend up to 3 zeroes, so if the value is 8, 
    #you'll get 008, if the value is 80, you'll get 080 etc.
    #This needs to be done or APRS will deny the packets as invalid. 
    #The other things is, everytime you send the telemetry,
    #a sequence number has to change, it's defined as T# in a APRS protocol. 
    #We will automate this next.
    
    #Check if file exist
    if [ ! -f "/tmp/sequence_number.txt" ]; then
     touch /tmp/sequence_number.txt
    fi
    
    #Read sequence number. Everytime the scripts runs, the number will 
    #rise by 1 until it comes
    #to 1000 and then returns back to 0. Everytime the script
    #will run, a sequence number will change.
    read num < /tmp/sequence_number.txt
    num=$((num + 1))
    if (( num == 1000 )); then
     num=0
    fi 
    
    #Finally, we can start assembling the data. 
    #$senduser goes to %s, $num goes to first %03d and $temp goes to 
    #the last %03d in the string. 
    printf -v t1 "%s>APN001,TCPIP*:T#%03d,%03d,000,000,000,000,00000000" "$senduser" "$num" "$temp"
    
    #Define telemetry parameters
    t2="$user>APN001,TCPIP*::$senduser :PARM.CPU Temp"
    
    #Define telemetry units
    t3="$user>APN001,TCPIP*::$senduser :UNIT.Deg.C"
    
    #Add telemetry coefficient so the APRS protocol can convert your raw values
    #into real value.
    #We get the value in 3 whole numbers and we need to define coefficient so 
    #the APRS protocol
    #will know how to display the value. We add 0.1 to the second field, means
    #if the value is 452, the temperature will be displayed as 45.2
    t4="$user>APN001,TCPIP*::$senduser :EQNS.0,0.1,0,0,0,0,0,0,0,0,0,0,0,0,0"
    
    #Send bits and project comment
    t5="$user>APN001,TCPIP*::$senduser :BITS.00000000,$projectcomment"
    
    #Another tricky part is, $senduser total lenght has to be 9 characters. 
    #For example
    #If my $senduser=S55MA-10 means it's only 8 characters long and we need 
    #to add 1 space to it. S55MA-10 :PARM
    #If my $senduser=S55MA means it's only 5 characters long and we need to 
    #add 4 spaces to it S55MA    :PARM
    #The same goes for UNIT, EQNS and BITS
    
    #Send data to the server
    #For telemetry to work we need to have an object before, from previous script.
    #We'll only send an object and telemetry non value data every hour so we don't 
    #spam the network.
    #We need to compare dates to see if 1 hour is past.
    
    #Check if file exist
    if [ ! -f "/tmp/date.txt" ]; then
       echo 0 > /tmp/date.txt
    fi
    
    #calculate time difference
    read olddate < /tmp/date.txt
    date="$(date +%s)"
    diff="$(echo "$date - $olddate" | bc)"
    
    #If 3600 is past, execute the first command, else other
    if [ "$diff" -gt 3600 ]; then
       printf "%s\n" "$aprsauth" "$data" | ncat --send-only $server $port #this is your QTH object from the first script
       printf "%s\n" "$aprsauth" "$t1" "$t2" "$t3" "$t4" "$t5" | ncat --send-only $server $port 
       echo "$date" > /tmp/date.txt
    else
       printf "%s\n" "$aprsauth" "$t1" | ncat --send-only $server $port
    fi
    #Write the last sequence number.
    echo "$num" > /tmp/sequence_number.txt
    

    Telemetry should form on aprs.fi, for example: https://aprs.fi/telemetry/a/S55MA-10
    Note, formatting in script might be broken due html formatting, here is a raw script: https://pastebin.com/24CaMXLT

    I’ve bought an affordable geiger counter board that fits on a Raspberry pi zero (https://www.tindie.com/products/granzscientific/raspberry-pi-zero-iot-geiger-counter/).  I’ve modified original software and added some scripts to send radiation readings to the APRS network. I’ve also added a Munin plugin. Go to the github project site for instructions: https://github.com/s55ma/granzscientific-geiger-counter-APRS

    Pi-Hole is a DNS based ad blocker. You can install it on a Debian based Linux distributions. To use it together with a PfSense firewall you need to change a few firewall settings:

    • Login to your PfSense and go to System -> General Setup:

    In the first DNS Server field insert the IP of your Pi-Hole computer and save changes

    • Go to Services -> DNS Resolver:

    Tick Enable DNS resolver

    Tick Enable DNSSEC Support

    Tick Enable Forwarding Mode (this will tell the PfSense to use a DNS server that we configured in a general settings in the previous step)

    Save and that’s it.

    This post will show you how to generate weather data from LA Crosse WS2300 series weather stations for submission to the APRS network.

    APRS software I’m using is Xastir, but you can use this setup to push the weather data to other APRS applications also. Digipeater mode is already set up in Xastir. This post will not cover digipeating WX data.

    1. Install packages

    apt-get update
    
    apt-get install  bc ncat unzip gcc build-essential

    2. Download open2300 and compile fetch2300

    Fetch2300 is part of open2300, it’s used to connect to the weather station and return the data. Credit goes to Kenneth Lavrsen (http://www.lavrsen.dk/foswiki/bin/view/Open2300)

    wget -O "open2300-1-10.zip" https://sourceforge.net/projects/open2300/files/open2300/1.10/open2300-1.10.zip/download"
    
    unzip open2300-1-10.zip
    
    cd open2300-1.10
    
    make fetch2300
    
    cp fetch2300 /usr/local/bin/fetch2300



    3. Edit  and rename open2300 config file named open2300-dist.conf or copy mine to /etc/open2300/open2300.conf

    mkdir -p /etc/open2300
    
    nano /etc/open2300/open2300.conf
    SERIAL_DEVICE /dev/ttyUSB1 #/dev/ttyS0, /dev/ttyS1, COM1, COM2 etc
    TIMEZONE 1 # Hours Relative to UTC. East is positive, west is negative
    WIND_SPEED km/h # select MPH (miles/hour), m/s, or km/h
    TEMPERATURE F # Select C or F
    RAIN IN # Select mm or IN
    PRESSURE hPa # Select hPa, mb or INHG

    Note: make sure you select the correct SERIAL_DEVICE in the config. The station in my setup

    is connected via USB to RS232 converter so the device is ttyUSB0. Also, don’t change the units, bash script will automatically convert them to be compatible with APRS network.

    4. Copy bash script to desired location

    mkdir -p /root/ws2300/
    
    nano wxdata_v1.6.sh
    #!/bin/bash
    
    #This script reads weather data via fetch program which is part of Open2300 suite written by Kenneth Lavrsen (http://www.
    #lavrsen.dk/foswiki/bin/view/Open2300/WebHome).
    #It outputs the right data needed to feed Xastir for APRS weather reports. The scripts utilizes Ncat utility as server to
    #serve the fetched output to Xastir.
    #Fetched Data is pushed to Ncat server and then to Xastir. (Fetched data -> Ncat server -> Xastir)
    #Ncat is part of Nmap, get it by installing Nmap.
    #This script should work for LaCrosse weather stations, WS23xx series. Testing was done with WS2307.
    #Written by S55MA and S56IUL, May 2016
    
    #DEFINE VARIABLES
    host="127.0.0.1"
    port="1234"
    
    #Start the Ncat server
    chkncat=$(netstat -ant | grep $host:$port | grep -c LISTEN)
    if [ "$chkncat" -ge "1" ]
    then
    echo "ncat already running, nothing to do"
    else
    nohup ncat -k -l --broker $host $port &>/dev/null &
    fi
    
    #Start while loop
    while true; do
    
    echo "start `date`"
    
    datetime=$(date '+%Y%m%d%H%M%S')
    ws2300config="/etc/open2300/open2300.conf"
    /usr/local/bin/fetch2300 $ws2300config > /tmp/wxdata-"$datetime".tmp
    fetch_path="/tmp/wxdata-$datetime.tmp"
    chkfile=$(ls -la $fetch_path | awk -F ' ' '{ print $5 }')
    
    if [ "$chkfile" -le "43" ]
    then
    echo "No Data"
    sleep 30
    else
    tempF=$(cat "$fetch_path" | grep To | grep -v 'min\|max\|DRtot\|TRtot' | awk '{print $2}')
    temp1=$(echo "$tempF" | awk '{ printf ("%d\n",$1 + 0.5)}')
    if [ "$temp1" -ge "99" ] || [ "$temp1" -le "-99" ]
    then
    temp="$temp1"
    else
    if [ "$temp1" -le "-1" ]
    then
    if [ "$temp1" -ge "-9" ]
    then
    temp2=$(echo "$temp1" | sed 's/[-]//g')
    temp=$(echo -0"$temp2")
    else
    temp2=$(echo "$temp1" | sed 's/[-]//g')
    temp=$(echo -"$temp1")
    fi
    else
    temp=$(echo 0"$temp1")
    fi
    fi
    
    windspeed2=$(cat "$fetch_path" | grep -m1 WS | grep -v 'min\|max\|DRtot\|TRtot'| awk '{print $2/1.609344}' | awk '{ printf ("%d\n",$1 + 0.5)}')
    if [ "$windspeed2" -le "9" ]
    then
    windspeed=$(echo 00"$windspeed2")
    else
    if [ "$windspeed2" -le "99" ]
    then
    windspeed=$(echo 0"$windspeed2")
    else
    windspeed=$(echo "$windspeed2")
    fi
    fi
    
    winddirection2=$(cat "$fetch_path" | grep DIR0 | awk '{print $2}' | sed 's/\..*$//')
    if [ "$winddirection2" -le "9" ]
    then
    winddirection=$(echo 00"$winddirection2")
    else
    if [ "$winddirection2" -le "99" ]
    then
    winddirection=$(echo 0"$winddirection2")
    else
    winddirection=$(echo "$winddirection2")
    fi
    fi
    
    rain1h=$(cat "$fetch_path" | grep R1h | grep -v 'min\|max' | awk '{print $2}' | sed 's/[.]//g')
    rain24h=$(cat "$fetch_path" | grep R24h | grep -v 'min\|max' | awk '{print $2}' | sed 's/[.]//g')
    
    airpressureR=$(cat "$fetch_path" | grep RP | grep -v 'min\|max' | awk '{print $2}')
    airpressure2=$(echo "scale=1;$airpressureR / 1" | bc | sed 's/[.]//g')
    if [ "$airpressure2" -le "9999" ]
    then
    airpressure=$(echo 0"$airpressure2")
    else
    airpressure=$(echo "$airpressure2")
    fi
    
    relhumidity=$(cat "$fetch_path" | grep RHo | grep -v 'min\|max' | awk '{print $2}' | sed 's/\..*$//')
    
    #Combine variables to forge Xastir string
    xastir="c${winddirection}s${windspeed}t${temp}r${rain1h}p${rain24h}b${airpressure}h${relhumidity}xDvs"
    printf "%s\n" "$xastir" | ncat --send-only $host $port
    echo "$xastir"
    sleep 3
    
    rm -f /tmp/wxdata-*.tmp
    
    echo "stop `date`"
    echo "-----------------------------------"
    fi
    
    done
    
    #EOS



    If there are some formatting mistakes, the script is also available on pastebin: http://pastebin.com/29q8epF8

    5. Start the script

    /root/ws2300/wxdata_v1.6.sh

    You should see output similar to that:

    start Tue May 3 00:36:47 CEST 2016
    c112s013t048b10037h85xDvs

    Leave the script running, open another terminal and check if ncat is getting data:

    ncat localhost 1234

    Wait a few seconds and you should get the result similar to that:

    c112s018t048b10037h85xDvs



    6. Go to Xastir and add the WX interface

    Interface -> Interface Control -> Add -> Networked WX

    WX Host: 127.0.0.1

    WX Port: 1234

    Save and start the interface.

    wx_interface

    7. Go to Xastir, View -> Own Weather Data

    You should see your own weather data from the station

    wx_data

    8. Start the script at boot and run it in background

    Open /etc/rc.local and add

    screen -d -m /root/ws2300/wxdata_v1.6.sh

    Save and exit

    Note: make sure you set your own path of the script location

     

    My HW/SW setup:

    Dongle: SDR USB Dongle (Realtek RTL2832U R820T chipset, other SDR dongles may also work). Search Ebay for RTL2832U dongles. They should all work.

    OS: Windows 7, 64bit

    Capture software: SDR# from sdrsharp.com

    Decoder: AFSK1200

    Note: Don’t install any software drivers that came with the SDR Dongle. Uninstall the drivers, if you already installed them.

    1. Setup stereo mix:

    Stereo mix is used to forward output sound to the microphone input. We need this, because AFSK1200 decoder will be listening to the microphone input. Open sound options in control panel or just go to start and enter mmsys.cpl. Using USB headset will not work, you need analog speakers. There are some workarounds to use USB headsets but I haven’t tried them yet.

    Playback tab: set speakers to the default device.

    speakers

    Recording tab: if you don’t see the “Stereo mix device”, it’s probably hidden.

    • Right click anywhere in the field where devices are listed and tick “Show disabled devices“, “Show disconnected devices. Stereo mix shold be available now.
    • Right click on it and select “Enable“.

    recording2

    2. Download  and configure SDR# software:

    • Download http://sdrsharp.com/downloads/sdr-install.zip
    • Extract it and run install.bat
    • Plug in your SDR dongle, go to sdrsharp folder and run zadig.exe. Go to Options and tick “List all devices“. Select “Bulk-In, Interface (Interface 0)” and click “Install Driver”. (On my screenshot, you can see “Reinstall Driver, because I already installed it). Note: You will need to install driver again if you replug the dongle in another USB port.

    zadig

    • Run SDRSharp.exe
    • Source -> RTL-SDR (USB)
    • Radio -> NFM, enable Squelch and set it between 50 and 80, you can increase or decrease it depending on your surrounding environment
    • Frequency Manager -> New -> add the frequency you want to monitor, in my case it’s 144.800 Mhz.
    • Click on Play button at the top of SDR# You will see spikes when something is transmitting on the frequency

    sdrsharp

    3. Decode packets with AFSK 1200 Decoder:

    • Download AFSK 1200 Decoder
    • Select Input and choose Stereo mix
    • Click play button. You are now decoding APRS packets

    afsk1200

    Don’t forget to disable stereo mix and set the default playback device as you had before when you finish decoding.

    I used my RaspberryPI to setup an APRS digipeater. The software I used is called Xastir. The problem is, there are no good default maps to use in Xastir.

    This tutorial will guide you how to install OSM maps into Xastir software. Maps are generated on a Windows machine, then transferred to a Linux machine where Xastir is running.

    TL;DR version:

    1. Download Taho application for Windows.

    2. Select area, copy bbox text.

    3. Paste bbox text to Taho, click on bbox button, select parameters and click on make maps.

    4. Upload generated .inf and .jpg files to your Xastir map folder.

    5. Download inf2geo.pl to your linux machine and convert .inf files to .geo files.

    6. Start or restart Xastir, select your map and apply.

     

    Detailed version:

    1. Download Taho application for Windows (Version 4.01 didn’t work on my PC, you should download older versions, if you can’t run the newest version).

    2. When you launch the Taho application, it will also open the bbox tool site.

    3. On the bbox tool site, center map to your desired location and click button “select area”. Select your area.

    Note: If you select too big area, you won’t be able too select top zoom levels in the next steps.

    bboxtool

    4. Copy code in the grey box to your clipboard.

    greybox

     

    5. Open Taho application and paste the code into “Get from <bbox…>” field. Click on the bbox button now. It should populate coordinates into Taho application. Select UI-View in Kal.-Files, .jpg for file type, zoom level (16 is good for small city), size (should be free, whole area in 1 file), define path for saving your maps and click on make maps button.

    steps

     

    6. Each selected zoom level generates separate .jpg and .inf files in your defined maps path (step above).

    7. Xastir doesn’t know how to handle .inf files so we need to convert them to .geo format. Upload your .jpg and .inf files to Xastir map folder. In my case, maps are located in  /usr/share/xastir/maps Fire up your linux console and

    Download inf2geo.pl converter and convert .inf files:

    sudo cd /usr/share/xastir/scripts
    sudo wget https://raw.githubusercontent.com/mgrennan/xastir/master/scripts/inf2geo.pl
    sudo chmod +x inf2geo.pl
    sudo ./inf2geo.pl /usr/share/xastir/maps/yourmap.inf
    

    By now, you should have yourmap.geo file in /usr/share/xastir/maps
    Open .geo file with your favourite editor and correct the path if you have to.

    FILENAME    maps/yourmap.jpg
    TIEPOINT    0           0       16.0645 45.8288333333333
    TIEPOINT    5631        5887    14.661666666667        46.8525
    IMAGESIZE   5632        5888
    #5632x5888
    #
    # Converted from a .INF file by WE7U's inf2geo.pl script
    #
    

    Note: If you change the name of the file, you also have to change FILENAME in yourmap.geo accordingly.

    8. Start or restart Xastir, go to Map -> Map Chooser -> select your map -> Apply -> profit.