add web server, rtsp server, other fixes

This commit is contained in:
Alex 2024-12-13 09:26:47 -04:00
parent 1ec4b47da6
commit 7169c6ce31
6 changed files with 246 additions and 33 deletions

View File

@ -7,10 +7,11 @@ DRY_RUN=false
# Define dependencies
DEPENDENCIES := nano htop nload sshpass python3-pip git ninja-build pkg-config gcc g++ systemd dkms python3-all python3-all-dev libpcap-dev libsodium-dev libevent-dev python3-pip python3-pyroute2 python3-msgpack \
python3-future python3-twisted python3-serial python3-jinja2 iw virtualenv debhelper dh-python fakeroot build-essential python3-autobahn
python3-future python3-twisted python3-serial python3-jinja2 iw virtualenv debhelper dh-python fakeroot build-essential python3-autobahn python3-websockets node gstreamer1.0-tools gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-rtsp libgstrtspserver-1.0-0 python3-gi
# Define installation targets and options
.PHONY: enable install interactive dependencies uninstall default full-install spirilink-driver spirilink-software setup-webapp-service configure-spirilink
.PHONY: enable install interactive dependencies uninstall default full-install spirilink-driver spirilink-software setup-webapp-service configure-spirilink install-key setup-rtsp-service
default: interactive install
@ -43,6 +44,8 @@ full-install:
$(MAKE) spirilink-software
$(MAKE) configure-spirilink
$(MAKE) setup-webapp-service
$(MAKE) install-key
$(MAKE) setup-rtsp-service
@echo "Full installation complete."
manual-select:
@ -55,7 +58,9 @@ manual-select:
@echo "[5] SpiriLink Software"
@echo "[6] Configure SpiriLink"
@echo "[7] Setup WebApp Service"
@echo "[8] Exit"
@echo "[8] Install gs.key"
@echo "[9] Setup RTSP Service"
@echo "[0] Exit"
@read -p "Enter your choices separated by spaces (e.g., 1 2 3): " choices; \
selected="$$choices"; \
for choice in $$selected; do \
@ -66,13 +71,25 @@ manual-select:
if [ "$$choice" = "5" ]; then $(MAKE) spirilink-software; fi; \
if [ "$$choice" = "6" ]; then $(MAKE) configure-spirilink; fi; \
if [ "$$choice" = "7" ]; then $(MAKE) setup-webapp-service; fi; \
if [ "$$choice" = "8" ]; then exit 0; fi; \
if [ "$$choice" = "8" ]; then $(MAKE) install-key; fi; \
if [ "$$choice" = "9" ]; then $(MAKE) setup-rtsp-service; fi; \
if [ "$$choice" = "0" ]; then exit 0; fi; \
done;
install:
@echo "Starting installation..."
@echo "Installation complete."
# Install gs.key
.PHONY: install-key
install-key:
@echo "Installing gs.key"
@if [ -f $(CURDIR)/gs.key ]; then \
$(SUDO) cp $(CURDIR)/gs.key /etc/; \
else \
echo "Error: gs.key not found in deployment folder."; \
fi;
# Install dependencies from the array
.PHONY: dependencies
dependencies:
@ -127,46 +144,42 @@ configure-spirilink:
echo "unmanaged-devices=interface-name:spir0" | $(SUDO) tee -a /etc/NetworkManager/NetworkManager.conf > /dev/null; \
fi
@$(SUDO) systemctl restart NetworkManager
@echo "Configuring wifibroadcast default interface..."
@$(SUDO) bash -c 'echo "WFB_NICS=\"spir0\"" > /etc/default/wifibroadcast'
@echo "SpiriLink configuration complete."
# Install SpiriLink software
.PHONY: spirilink-software
spirilink-software:
@echo "\nInstalling SpiriLink software..."
@if [ -d ~/tmp/spirilink ]; then \
@echo "Installing SpiriLink software..."
@if [ -d ~/home/spiri/spirilink ]; then \
read -p "SpiriLink software source already exists. Reinstall? (Y/N): " reinstall; \
if [ "$$reinstall" = "Y" ] || [ "$$reinstall" = "y" ]; then \
cd ~/tmp/spirilink && git pull && \
$(SUDO) make deb && $(SUDO) dpkg -i ~/tmp/spirilink/deb_dist/wfb*.deb; \
cd ~/home/spiri/spirilink && git pull && \
$(SUDO) ./scripts/install_gs.sh spir0; \
$(SUDO) bash -c 'echo "WFB_NICS=\"spir0\"" > /etc/default/wifibroadcast'; \
$(SUDO) cp ~/home/spiri/spirilink/wifibroadcast.cfg /etc/; \
else \
echo "Skipping SpiriLink software installation."; \
fi; \
else \
git clone https://git.spirirobotics.com/aepko/SpiriLink.git ~/tmp/spirilink && \
cd ~/tmp/spirilink && \
$(SUDO) make deb && $(SUDO) dpkg -i ~/tmp/spirilink/deb_dist/wfb*.deb; \
git clone https://git.spirirobotics.com/aepko/SpiriLink.git ~/home/spiri/spirilink && \
cd ~/home/spiri/spirilink && \
$(SUDO) ./scripts/install_gs.sh spir0; \
$(SUDO) bash -c 'echo "WFB_NICS=\"spir0\"" > /etc/default/wifibroadcast'; \
$(SUDO) cp ~/home/spiri/spirilink/wifibroadcast.cfg /etc/; \
fi;
@echo "\nSpiriLink software installed."
@echo "SpiriLink software installed."
# Set up web app service
.PHONY: setup-webapp-service
setup-webapp-service:
@echo "Setting up web app service..."
@if [ -d ~/spiri-base ]; then \
cd ~/spiri-base && git pull || (echo "Error updating repository. Check network and repository access." && exit 1); \
@if [ -d ~/Spiri-Base ]; then \
cd ~/Spiri-Base && git pull || (echo "Error updating repository. Check network and repository access." && exit 1); \
else \
git clone https://git.spirirobotics.com/aepko/Spiri-Base.git ~/spiri-base || (echo "Error cloning repository. Check network and repository access." && exit 1); \
cd ~/spiri-base && git sparse-checkout init --cone && git sparse-checkout set .output; \
fi;
@if [ -d ~/spiri-base/.output ]; then \
$(SUDO) mkdir -p /var/www/webapp; \
$(SUDO) cp -r ~/spiri-base/.output/* /var/www/webapp/; \
else \
echo "Error: .output folder not found. Ensure the repository contains the necessary files."; \
exit 1; \
git clone https://git.spirirobotics.com/aepko/Spiri-Base.git ~/Spiri-Base || (echo "Error cloning repository. Check network and repository access." && exit 1); \
cd ~/Spiri-Base && git sparse-checkout init --cone && git sparse-checkout set .output; \
fi;
@if [ -f $(CURDIR)/webapp.service ]; then \
$(SUDO) cp $(CURDIR)/webapp.service /etc/systemd/system/webapp.service; \
@ -175,7 +188,22 @@ setup-webapp-service:
else \
echo "Error: webapp.service not found in deployment folder."; \
fi;
@echo "\nWeb app service set up and running."
@echo "Web app service set up and running."
# Set up RTSP service
.PHONY: setup-rtsp-service
setup-rtsp-service:
@echo "Setting up RTSP server..."
$(SUDO) mkdir -p ~/rtsp
$(SUDO) cp $(CURDIR)/scripts/rtsp_server.py ~/rtsp/
@if [ -f $(CURDIR)/scripts/rtsp-server.service ]; then \
$(SUDO) cp $(CURDIR)/scripts/rtsp-server.service /etc/systemd/system/rtsp-server.service; \
$(SUDO) systemctl enable rtsp-server.service; \
$(SUDO) systemctl start rtsp-server.service; \
else \
echo "Error: rtsp-server.service not found in scripts folder."; \
fi;
@echo "RTSP server set up and running."
# Uninstall all installed components
.PHONY: uninstall

1
gs.key Normal file
View File

@ -0,0 +1 @@
ЛЗэn<EFBFBD>Єj<EFBFBD><EFBFBD><EFBFBD> љ<C2A0>Ю+м<><D0BC>И GВ<5F>Ќ{FФ<>a<EFBFBD>ћp<D19B>tzfш<ц@НkОЕВQSz<53>ЂtЂc

14
rtsp-server.service Normal file
View File

@ -0,0 +1,14 @@
[Unit]
Description=RTSP Server for FPV Video
After=network-online.target
[Service]
ExecStart=/usr/bin/python3 /home/spiri/rtsp/rtsp_server.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
Type=simple
[Install]
WantedBy=multi-user.target

35
rtsp_server.py Normal file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env python3
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GLib
class CustomRTSPMediaFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self):
super().__init__()
self.set_shared(True)
def do_create_element(self, url):
pipeline = (
"udpsrc port=5600 caps=\"application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H265\" ! "
"rtph265depay ! h265parse ! rtph265pay name=pay0 pt=96"
)
return Gst.parse_launch(pipeline)
class CustomRTSPServer(GstRtspServer.RTSPServer):
def __init__(self):
super().__init__()
factory = CustomRTSPMediaFactory()
mount_points = self.get_mount_points()
mount_points.add_factory("/video", factory)
self.attach(None)
def main():
Gst.init(None)
server = CustomRTSPServer()
loop = GLib.MainLoop() # Updated to GLib
print("RTSP Server running at rtsp://127.0.0.1:8554/video")
loop.run()
if __name__ == "__main__":
main()

View File

@ -1,15 +1,15 @@
[Unit]
Description=SpiriBase WebApp Service
Description=Spiri Base Node.js Application
After=network.target
[Service]
Type=simple
WorkingDirectory=/var/www/webapp
ExecStart=/usr/bin/node /var/www/webapp/.output/server/index.mjs
Restart=on-failure
ExecStart=/usr/bin/node /home/spiri/Spiri-Base/.output/server/index.mjs
WorkingDirectory=/home/spiri/Spiri-Base
Restart=always
User=spiri
Group=spiri
Environment=NODE_ENV=production
User=www-data
Group=www-data
Environment=PORT=80
[Install]
WantedBy=multi-user.target

135
wifibroadcast.cfg Normal file
View File

@ -0,0 +1,135 @@
[common]
primary = True # Set to False if you use several wfb instances on one card. Only primary instance will set radio channel.
log_file = None # Set to "wifibroadcast.log" to disable log to stdout
binary_log_file = None # Machine readable log for post-processing
# File name should have '%%s' inside for profile mapping.
# For example: 'binlog_%%s.log'
set_nm_unmanaged = True # Set radio interface in 'unmanaged state' in NetworkManager
radio_mtu = 1445 # Used for mavlink aggregation and for tunnel packets - should be less or equal to MAX_PAYLOAD_SIZE, don't change if doubt
tunnel_agg_timeout= 0.005 # aggragate tuntap packets if less than radio_mtu but no longer than 5ms
mavlink_agg_timeout = 0.1 # aggragate mavlink packets if less than radio_mtu but no longer than 100ms
mavlink_err_rate = True # If true then inject RX error rate else absolute values
log_interval = 1000 # [ms] Default interval which wfb_rx/tx use for statistics reporting
tx_sel_rssi_delta = 3 # [dB] hysteresis for antenna selection by RSSI
tx_sel_counter_abs_delta = 3 # [pkt] hysteresis for antenna selection by RX packet counter
tx_sel_counter_rel_delta = 0.1 # default is max(3 packets or 10% of packets from the best antenna)
tx_rcv_buf_size = 2097152 # UDP SO_RCVBUF. Set 0 to use net.core.rmem_default. Increase in case of non-cbr data stream
# This should not be greater than net.core.rmem_max
wifi_channel = 161 # radio channel @5825 MHz, range: 5815-5835 MHz, width 20MHz
# Also you can set own frequency channel for each wifi card, for example:
# {'wlan0': 161, 'wlan1': 165}
wifi_region = 'BO' # Set CRDA region
wifi_txpower = None # Leave None to use default power settings from driver.
# There is a special value 'off' for RX only cards.
# For 8812au set to -dBm * 100. I.e for 30dBm set to -3000
# For 8812eu set to dBm * 100. I.e for 30dBm set to 3000
# Also you can set own txpower for each wifi card, for example:
# {'wlan0': -100, 'wlan1': 100, 'wlan2': 'off'}
temp_measurement_interval = 10 # [s] (8812eu only) Internal RF path temp measurement.
temp_overheat_warning = 60 # [*C] (8812eu only) Overheat warning threshold.
[gs]
streams = [{'name': 'video', 'stream_rx': 0x00, 'stream_tx': None, 'service_type': 'udp_direct_rx', 'profiles': ['base', 'gs_base', 'video', 'gs_video']},
{'name': 'mavlink', 'stream_rx': 0x10, 'stream_tx': 0x90, 'service_type': 'mavlink', 'profiles': ['base', 'gs_base', 'mavlink', 'gs_mavlink']},
{'name': 'tunnel', 'stream_rx': 0x20, 'stream_tx': 0xa0, 'service_type': 'tunnel', 'profiles': ['base', 'gs_base', 'tunnel', 'gs_tunnel']}
]
stats_port = 8003 # used by wfb-cli
api_port = 8103 # public JSON API
link_domain = "default"
###########################################################################################################################
# Low level profiles can be used to build top level profiles via inheritance #
# You can define any number of them and split options between them as you want - only resulting set of options has matter #
###########################################################################################################################
## Low level profiles have protocol-dependant fields
[base]
stream_rx = None
stream_tx = None
keypair = None
mirror = False # Set to true if you want to mirror packet via all cards for redundancy. Not recommended if cards are on one frequency channel.
# Radio settings for TX and RX
bandwidth = 20 # bandwidth 20 or 40 MHz
force_vht = False # Use VHT for 20 and 40 MHz bandwidth
# Radiotap flags for TX:
short_gi = False # use short GI or not
stbc = 1 # stbc streams: 1, 2, 3 or 0 if unused
ldpc = 1 # use LDPC FEC. Currently available only for 8812au and must be supported both on TX and RX.
mcs_index = 1 # mcs index
# Packet queueing control
use_qdisc = False # Use or bypass kernel qdisc. Set to True if you want to use traffic shaper
fwmark = 0 # If use qdisc then set fwmark to this value for data packets and to fwmark + 1 for FEC packets
control_port = 0 # Override in tx sections if you want to manually control wfb_tx processes via wfb_tx_cmd utility
[gs_base]
keypair = 'gs.key'
[radio_base]
frame_type = 'data' # Use data or rts frames
fec_k = 1 # FEC K (For tx side. Rx will get FEC settings from session packet)
fec_n = 2 # FEC N (For tx side. Rx will get FEC settings from session packet)
fec_timeout = 0 # [ms], 0 to disable. If no new packets during timeout, emit one empty packet if FEC block is open
fec_delay = 0 # [us], 0 to disable. Issue FEC packets with delay between them.
[video]
frame_type = 'data' # Use data or rts frames
fec_k = 8 # FEC K (For tx side. Rx will get FEC settings from session packet)
fec_n = 12 # FEC N (For tx side. Rx will get FEC settings from session packet)
fec_timeout = 0 # [ms], 0 to disable. If no new packets during timeout, emit one empty packet if FEC block is open
fec_delay = 0 # [us], 0 to disable. Issue FEC packets with delay between them.
peer = None
[mavlink]
log_messages = False # Log all messages to binary log for post processing
frame_type = 'data' # Use data or rts frames
fec_k = 1 # FEC K (For tx side. Rx will get FEC settings from session packet)
fec_n = 2 # FEC N (For tx side. Rx will get FEC settings from session packet)
fec_timeout = 0 # [ms], 0 to disable. If no new packets during timeout, emit one empty packet if FEC block is open
fec_delay = 0 # [us], 0 to disable. Issue FEC packets with delay between them.
peer = None
osd = None
inject_rssi = True # inject RADIO_STATUS packets
mavlink_sys_id = 3 # for injected rssi packets
mavlink_comp_id = 68 # MAV_COMP_ID_TELEMETRY_RADIO
call_on_arm = None # call program on arm
call_on_disarm = None # call program on disarm
mavlink_tcp_port = None # listen for connections from QGC or from onboard computer
[tunnel]
frame_type = 'data' # Use data or rts frames
fec_k = 1 # FEC K (For tx side. Rx will get FEC settings from session packet)
fec_n = 2 # FEC N (For tx side. Rx will get FEC settings from session packet)
fec_timeout = 0 # [ms], 0 to disable. If no new packets during timeout, emit one empty packet if FEC block is open
fec_delay = 0 # [us], 0 to disable. Issue FEC packets with delay between them.
[gs_video]
fwmark = 20 # traffic shaper label
peer = 'connect://127.0.0.1:5600' # outgoing connection for video sink (GS)
[gs_mavlink]
fwmark = 10 # traffic shaper label
peer = 'connect://127.0.0.1:14550' # outgoing connection
# peer = 'listen://0.0.0.0:14550' # incoming connection
# osd = 'connect://127.0.0.1:14551' # mirroring mavlink packets to OSD
[gs_tunnel]
fwmark = 30 # traffic shaper label
ifname = 'gs-wfb'
ifaddr = '10.5.0.1/24'
default_route = False