Tuesday, July 8, 2025

How to Stream RTSP / Webcam / IP Camera Over the Web

I had a Hikvision IPC-B120 that provides a simple RTSP stream, which I could view in VLC. I also wanted to see my Logitech BRIO’s feed in a browser—without having to start a Video Call session.


To do this, I pull the RTSP (video/audio) feed from each camera, pipe it through FFmpeg to convert it into an MPEG-TS stream, and then serve it over WebSocket using JSMpeg. On my Raspberry Pi 5, I run two systemd services (one per camera) that use websocat to listen for WebSocket connections. When a client connects, websocat launches FFmpeg to start the conversion and forwards the stream; when the client disconnects, FFmpeg automatically stops.




# /etc/systemd/system/rtsp-ws.service

[Unit]

Description=On-demand WebSocket→FFmpeg bridge for JSMpeg

After=network.target

[Service]

User=pi

Group=pi

ExecStart=/usr/local/bin/websocat \

  --binary \

  --exit-on-eof \

  -s 127.0.0.1:10000 \

  sh-c:'/usr/bin/ffmpeg -hide_banner -loglevel error -rtsp_transport tcp -i "rtsp://user:pass@Local.IP.Camera:Localport/URI/channels/101" -f mpegts -codec:v mpeg1video -bf 0 -r 25 pipe:1'

Restart=on-failure

[Install]

WantedBy=multi-user.target


# /etc/systemd/system/webcam-ws.service

[Unit]

Description=On-demand WebSocket→FFmpeg bridge for Brio webcam

After=network.target

[Service]

User=pi

ExecStart=/usr/local/bin/websocat \

  --binary \

  --exit-on-eof \

  -s 127.0.0.1:10001 \

sh-c:'WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/user/1000 /usr/bin/ffmpeg -hide_banner -loglevel error \

  -f v4l2 -framerate 30 -video_size 1920x1080 -i /dev/video0 \

  -f alsa -ac 2 -ar 44100 -i default \

  -f mpegts \

  -codec:v mpeg1video -bf 0 -r 30 \

  -codec:a mp2 \

  pipe:1'

Restart=on-failure

[Install]

WantedBy=multi-user.target



You can then create the related websocket proxy in apache and create a player file in html:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Live Camera (JSMpeg)</title>
<style>
/* fullscreen black background, centered content */
html, body {
margin: 0; padding: 0;
width: 100vw; height: 100vh;
background: #000;
display: flex;
align-items: center;
justify-content: center;
}

/* wrapper to constrain size, max 90% of viewport */
.player-container {
width: 90vw;
max-width: 1280px; /* or whatever max you like */
max-height: 90vh;
}

/* canvas will fill the container but keep its own aspect‐ratio */
.player-container canvas {
width: 100%;
height: auto;
display: block;
}
</style>
</head>
<body>
<div class="player-container">
<canvas id="videoCanvas"></canvas>
</div>

<script src="/jsmpeg.min.js"></script>
<script>
const url = (location.protocol==='https:'?'wss://':'ws://')
+ location.host + '/my-ws-prefix';

new JSMpeg.Player(url, {
canvas: document.getElementById('videoCanvas'),
autoplay: true,
audio: false
});
</script>
</body>
</html>

Sunday, May 25, 2025

How configure reverse proxy for Kodi web interface (chorus2)

 This tutorial goes over the steps to configure chorus2 behind nginx reverse proxy so you can remotely control your Kodi setup.

First Enable Kodi Web Interface and set a username and password in the settings as explained here

Then you can launch kodi web interface on Chromium and in the settings enable reverseproxy setup and also configure the port for your reverse proxy which usually is 443 for your nginx SSL.


For our nginx configuration, we need to note the following point in nginx reverse proxy docs:

A request URI is passed to the server as follows:

  • If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:
    location /name/ {
        proxy_pass http://127.0.0.1/remote/;
    }
    
  • If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:
    location /some/path/ {
        proxy_pass http://127.0.0.1;
    }
    
    Before version 1.1.12, if proxy_pass is specified without a URI, the original request URI might be passed instead of the changed URI in some cases.

Otherwise the way that kodi web interface tries to load images will not work.


## Kodi rewrite

# 1) WS for /jsonrpc (no prefix)
location ^~ /jsonrpc {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 360s;

proxy_pass http://10.10.1.5:9090;
}

# 2) Redirect bare /kodi → /kodi/
location = /kodi {
return 301 /kodi/;
}
# 3) Everything else under /kodi/ → strip prefix
location /kodi/ {
if ($request_uri ~ "^/kodi(?<after>/[^?]*)") {
set $new_path $after;
}

proxy_cache off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 300s;

proxy_pass http://10.10.1.5:10080$new_path$is_args$args;
}

####


 

Friday, April 18, 2025

How to Compile the Latest wf‑recorder on Raspberry Pi 5 (Debian 12 Wayland)

Debian 12 on Raspberry Pi 5 uses Wayland, so x11grab won’t work for screen capture. You can switch to wf-recorder, but the stock v0.3 in Debian’s repositories lacks newer flags like --overwrite

To get the latest wf-recorder with full feature support, you’ll need to build it from source. Here’s how:


# Install dependencies

sudo apt install g++ meson libavutil-dev libavcodec-dev libavformat-dev libswscale-dev libpulse-dev wayland-protocols libpipewire-0.3-dev

mkdir ~/src

cd ~/src

https://github.com/ammen99/wf-recorder/releases

wget https://github.com/ammen99/wf-recorder/releases/download/v0.5.0/wf-recorder-0.5.0.tar.xz

tar -xf wf-recorder-0.5.0.tar.xz

cd wf-recorder-0.5.0

meson setup build --prefix=/usr --buildtype=release --reconfigure

ninja -C build

# Install

cp ~/src/wf-recorder-0.5.0/build/wf-recorder /usr/local/bin


Now you can record the screen including audio using the following command:


wf-recorder --overwrite -a default -f file.mp4

Friday, February 21, 2025

How to set up Kodi with YouTube addon on Raspberry OS Debian 13

 In this post, we review how to run Kodi with Kodi Youtube Addon on Raspberry Pi 5. 

There are two versions of Kodi available on Raspberry Pi OS for Debain 12. `kodi` package installs v20.0 and `kodi21` installs version 21. Make sure to use v21 as it has resolved some bugs that causes glitches in video playback,

# Install Kodi21 

apt-get install kodi21 kodi21-inputstream-adaptive

# Download Kodi Youtube Plugin Repository 

cd /home/pi/Downloads

wget https://ftp.fau.de/osmc/osmc/download/dev/anxdpanic/repositories/repository.yt.testing_unofficial-2.0.7.zip

# Open Kodi -> Settings -> Addon -> Install from Zip File -> Home Folder -> Downloads -> Select the above zip file that you downloaded

#  Go Back (Settings -> Addon) -> Options (at bottom left) -> Check for Updates 

# Go Back (Settings -> Addon) -> Install from Repository -> Youtube Test Repo (Unofficial) -> Video add-ons -> Youtube -> Install

# add a Youtube API v3 API has described here. Just note that Publishing status in Audience should be Production. In Data Access section you need to enable Youtube related permissions. It will ask to login two times when trying to login on Youtube Addon for Kodi, and on your google device will show a warning that the app is not verified as explained here

#  Go to Home page -> Youtube -> Add-on settings (left side) -> API: fill API Key, API Id and API Secret by your Youtube API

# You can set Proxy setting in Kodi -> Setting -> System -> Internet Access

# Kodi turns on TV when it is started, and turns off TV when exitted. The behaviour can be set up in Kodi -> Setting -> System -> Interface

Kodi on debian 13 rpi comes with a basic web interface. To install the default chorus2 web interface:

tmp="$(mktemp -d)"

curl -L -o "$tmp/chorus2.zip" https://github.com/xbmc/chorus2/archive/refs/heads/master.zip

unzip -q "$tmp/chorus2.zip" -d "$tmp"

grep -n 'Kodi web interface - Chorus2' "$tmp"/chorus2-master/dist/addon.xml

mkdir -p ~/.kodi/addons

rm -rf ~/.kodi/addons/webinterface.default.new

cp -a "$tmp"/chorus2-master/dist ~/.kodi/addons/webinterface.default.new

if [ -d ~/.kodi/addons/webinterface.default ]; then mv ~/.kodi/addons/webinterface.default ~/.kodi/addons/webinterface.default.bak.$(date +%Y%m%d-%H%M%S); fi

mv ~/.kodi/addons/webinterface.default.new ~/.kodi/addons/webinterface.default

# To avoid your raspberry pi turning on your TV when it is rebooted, add hdmi_ignore_cec_init=1 to /boot/firmware/config.txt

Set up Kodi to pause streaming when the TV is switched to another source, or when the TV is powered off:

Kodi → Settings → System → Input → Peripherals → CEC Adapter


Action when switching to another source → Stop playback


When the TV is switched off→ Stop playback

# PartyMode addon can be used to set youtube addon to start up automatically when running Kodi

# piflare.com service can be used to connect raspberry pi to telegram so it starts kodi by running /youtube command


/scripts/youtube.py :

#!/home/pi/python/bin/python3

import os, sys, time

os.chdir('/home/pi')


os.environ["DISPLAY"] = ":0"

os.environ["WAYLAND_DISPLAY"] = "wayland-0"

os.environ["XDG_RUNTIME_DIR"] = "/run/user/1000"

os.environ["DBUS_SESSION_BUS_ADDRESS"] = "unix:path=/run/user/1000/bus"


os.system("pkill -9 -f 'chrome|chromium|google-chrome|chrome_crashpad_handler|kodi|kodi21.bin'")

os.system('/usr/bin/kodi &')

Tuesday, August 27, 2024

How to export Apple Health / Google Fit training activity to TCX format

I own a Xiaomi Smart Band 7, and recently, my Mi Fitness app stopped syncing running activities to Strava.

Mi Fitness supports syncing data with Apple Health, Strava, and Suunto. After exploring multiple solutions, I found a workaround to export running activities in TCX format and manually upload them to Strava, which accepts GPX, TCX, and FIT formats.

To do this, first, enable syncing with Apple Health in the Mi Fitness app. This will display your activities in Apple Health. While apps like HealthFit or RunGap can export Apple Health data, they require a purchase.

For a free option, install Google Fit and grant it access to Apple Health data. Once your activities are visible in Google Fit, use Google Takeout (https://takeout.google.com/) to export your Google Fit data. You’ll receive a zip file, which you can extract to find your daily activities in the "activities" folder in TCX format. Simply select the relevant TCX files and upload them manually to Strava.

Friday, March 1, 2024

How to disable Debian 12 sleep on production servers

 Debian 12 has power saver enabled by default which causes your server to go to sleep if there is no mouse / keyboard interaction. To resolve this issue as discussed here, edit /etc/gdm3/greeter.dconf-defaults and update the following vars and reboot your server:

sleep-inactive-ac-type='blank'

sleep-inactive-battery-type='blank'

Wednesday, February 21, 2024

Setup tunneled hotspot on Bookworm Raspberrypi using Wireguard, Network Manager and DNSmasq plugin

This blog post is an update to the original post from 2019 for Debian buster and bullseye.

 In this tutorial we use eth0 as our main internet, wireguard uses eth0 to connect to the server and created a tunneled connection which is used for hotspot by wlan0.

NetworkManager GUI Interface makes our work easy. No need to setup a dhcp server like isc-dhcp-server since NetworkManager has built-in dnsmasq-basic package installed and uses it for DHCP.

To setup hotspot, use Network icon in Raspberrypi to setup a wireless hotspot. For wireguard, you need to edit the hotspot connection and set MTU to 1420. Also, enable auto connect in General tab. Disable IPv6 in IPv6 tab if you are not using it. Set the range for your DHCP clients in IPv4 tab to 10.0.1.1 with mask 255.255.255.0 and gateway 10.0.1.1

To disable WPA Personal and force at least WPA2 Personal authentication use the following command:

nmcli device wifi list

nmcli con modify "Wi-Fi Hot" 802-11-wireless-security.proto rsn

then set a separate routing table for the hotspot ip range which is 10.0.1.0/24:

echo 200 INET2 >> /etc/iproute2/rt_tables
and setup wireguard to route the ip range from your hotspot through itself.

[Interface]
PrivateKey = YOUR.PRIVATE.KEY
Address = 10.10.0.6/24
PostUp = iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE; ip rule add from 10.0.1.0/24 table INET2 priority 100; ip route add default dev wg0 table INET2; ip route add 8.8.8.8/32 dev wg0; ip route add 8.8.4.4/32 dev wg0; iptables -t mangle -A FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu; iptables -t mangle -A FORWARD -i wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu; ip route flush cache
PreDown = iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE; ip rule del from 10.0.1.0/24 table INET2 priority 100; ip route del default dev wg0 table INET2; ip route del 8.8.8.8/32 dev wg0; ip route del 8.8.4.4/32 dev wg0; iptables -t mangle -D FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu; iptables -t mangle -D FORWARD -i wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu; ip route flush cache
Table = off
MTU = 1280

[Peer]
PublicKey = SERVER.PUBKEY
AllowedIPs = 0.0.0.0/0

Endpoint = IP:Port
PersistentKeepalive = 25

set net.ipv4.ip_forward=1 in /etc/sysctl.conf

Edit your upstream Network connections and set their DNS to 8.8.8.8,1.1.1.1 

This way, after a reboot your /etc/resolv.conf is correctly set to the above name servers by NetworkManager.

NetworkManager has a built-in dnsmasq-base package installed and we need to set it to use google name servers for our dhcp clients:

echo -e "dhcp-option=option:dns-server,8.8.8.8,8.8.4.4" > /etc/NetworkManager/dnsmasq-shared.d/dns.conf

Restart your raspberrypi to apply changes.

You can see a list of connected clients in /var/lib/NetworkManager/dnsmasq-wlan0.leases


ps aux | grep dnsmasq 

shows the dnsmasq and its parameters which is running by NetworkManager. 

How to resolve repeating keys issue on WayVNC bookworm

 When you connect to your bookworm 12 wayvnc VNC server from another country, there might be repeating key's issue if there is a packetloss in the connection. If the packet containing the key-release event gets dropped, it will be retransmitted and this will cause it to be delayed, perhaps enough to trigger the repeat.

 To resolve this issue, you can set kb_repeat_rate to 0 in wayfire config as explained here

edit /etc/wayfire/defaults.ini add 

kb_repeat_rate = 0

under [input] section in the file

then restart  your raspberrypi os to apply the new setting. 

Saturday, February 10, 2024

How to take a screenshot using ssh on Wayland Desktop

On debian 11 for raspberrypi and older versions, we can take a screenshot of the active desktop from SSH by using scrot package and setting DISPLAY environment variable to the display number which is 0.0 by default:

        DISPLAY=:0.0 scrot -o screenshot.jpg

or in python:

        os.environ["DISPLAY"] = ":0.0"

        os.system("scrot -o {}".format(picfile))

On Debian 12  for raspberrypi and later versions, Wayland is the default window manager and scrot won't work. grim package can be used which is installed by default. A similar method can be used to access the default wayland desktop by setting WAYLAND_DISPLAY and XDG_RUNTIME_DIR environment variables :

WAYLAND_DISPLAY=wayland-1 XDG_RUNTIME_DIR=/run/user/1000 grim screenshot.png

os.environ["WAYLAND_DISPLAY"] = "wayland-1"

os.environ["XDG_RUNTIME_DIR"] = "/run/user/1000"

os.system("grim {}".format(pngfile))

To find the correct values for these environment variables, use env command in your main desktop to find which values are set for these. without setting proper values, you get the following error when trying to get a screenshot on a non-active tty:

failed to create display

Thursday, February 8, 2024

How to set the default route on Debian 12 bookworm

 /etc/dhcpcd.conf file is missing on debian 12 bookworm OS for Raspberrypi.

To find the current metrics, use route -n

To find the network interface names use nmcli connection show

Then use the connection name of the connection you want to make the default route and set its connection metric to a higher number than others:

nmcli connection edit "Wired connection 1"

set ipv4.route-metric 102

save

quit


Wednesday, July 5, 2023

How to configure Eturnal TURN server with TLSv1.3 support on Debian 12

 eturnal is a turn server and an alternative to coturn. It can be installed on Debian using the instructions provided here

To use a static username and password, a script must be used to generate one that works with the defined secret code in the config file. 

The following python code can be used for such conversion:

import hmac

import hashlib

import base64

username = "1735686000"          # For credentials valid until 2025-01-01.

secret = "1pIFIj70BPsgBI92j5ux"  # As specified in your configuration file.

sha = hmac.new(secret.encode('utf-8'), username.encode('utf-8'), hashlib.sha1)

password = base64.b64encode(sha.digest()).decode('utf-8')

print(username)

print(password)


The following options can be used to disable older versions of tls to force tlsv1.3:

  ## TLS certificate/key files (must be readable by 'eturnal' user!):
  tls_crt_file: /opt/fullchain.pem
  tls_key_file: /opt/privkey.pem
  tls_options:
    - no_tlsv1
    - no_tlsv1_1
    - no_tlsv1_2

It is recommended to also uncomment the - recommended item in the blacklist section to blacklist local network ip addresses from turn and speed up connection.

Monday, July 3, 2023

How to Install coturn 4.6.2 with TLSv1.3 support on Debian 12

 TLSv1.3 support is added in coturn >4.6.2  . Debian 12 bookworm comes with coturn 4.6.1 which does support TLSv1.3. Docker version of coturn may be used to get the last version of coturn then, or a compilation from source is needed.  

In case of compiling from source, openssl 1.1.1 is needed to support TLSv1.3.

To compile the last version of coturn on Debian, follow these instructions:

apt-get install pkg-config build-essential libssl-dev libevent-dev libsystemd-dev -y

cd /usr/src

wget https://github.com/coturn/coturn/archive/refs/tags/4.6.2.tar.gz

tar -zxvf 4.6.2.tar.gz

cd coturn-4.6.2

./configure --prefix=/usr --confdir=/etc

make

make install

cp ./examples/etc/coturn.service /etc/systemd/system/

mv /etc/turnserver.conf.default /etc/turnserver.conf

systemctl daemon-reload

chown turnserver:turnserver /var/run/turnserver.pid

useradd turnserver -s /bin/false

systemctl enable coturn --now

service coturn status

Now, in the log file you should see:

INFO: TLS 1.3 supported

Jitsi provides a sample turnserver.conf file to use for media streaming and TURNS. The syntax file can be found here

The following configuration can be added to the /etc/turnserver.conf file to disable older versions of SSL/TLS incuding tlsv1.2 to enfore tlsv1.3 connections:

no-sslv3

no-tlsv1

no-tlsv1_1

no-tlsv1_2

A static user and password for turn can be defined using the following config:

lt-cred-mech

user=TURNUSER:TURNPASSWORD


Sunday, April 23, 2023

How to suppress opencv / gst-launch-1.0 nvarguscamerasrc GST_ARGUS warning / debug messages

 Jetson camera library always prints debug information:




GST_ARGUS: Creating output stream

CONSUMER: Waiting until producer is connected...

GST_ARGUS: Available Sensor modes :

GST_ARGUS: 3264 x 2464 FR = 21.000000 fps Duration = 47619048 ; Analog Gain range min 1.000000, max 10.625000; Exposure Range min 13000, max 683709000;

GST_ARGUS: 3264 x 1848 FR = 28.000001 fps Duration = 35714284 ; Analog Gain range min 1.000000, max 10.625000; Exposure Range min 13000, max 683709000;

GST_ARGUS: 1920 x 1080 FR = 29.999999 fps Duration = 33333334 ; Analog Gain range min 1.000000, max 10.625000; Exposure Range min 13000, max 683709000;

GST_ARGUS: 1640 x 1232 FR = 29.999999 fps Duration = 33333334 ; Analog Gain range min 1.000000, max 10.625000; Exposure Range min 13000, max 683709000;

GST_ARGUS: 1280 x 720 FR = 59.999999 fps Duration = 16666667 ; Analog Gain range min 1.000000, max 10.625000; Exposure Range min 13000, max 683709000;

GST_ARGUS: 1280 x 720 FR = 120.000005 fps Duration = 8333333 ; Analog Gain range min 1.000000, max 10.625000; Exposure Range min 13000, max 683709000;

GST_ARGUS: Running with following settings:

   Camera index = 0 

   Camera mode  = 2 

   Output Stream W = 1920 H = 1080 

   seconds to Run    = 0 

   Frame Rate = 29.999999 

GST_ARGUS: Setup Complete, Starting captures for 0 seconds

GST_ARGUS: Starting repeat capture requests.

CONSUMER: Producer has connected; continuing.


These prints are hardcoded in the source file of the camera module gstnvarguscamerasrc.cpp as explained here . The following commands can be used to disable these hardcoded messages and compile the module.

Find the corresponding version of your nvidia jetpack and download its public_sources file

cat /etc/nv_tegra_release

cd ~/src 

# for R32 (release), REVISION: 7.3 Driver Package (BSP) Sources:  https://developer.nvidia.com/embedded/linux-tegra-r3273

wget --trust-server-names https://developer.nvidia.com/downloads/remack-sdksjetpack-463r32releasev73sourcest210publicsourcestbz2

tar -jxvf public_sources.tbz2*

cd Linux_for_Tegra/source/public

tar -jxvf gst-nvarguscamera_src.tbz2

cd gst-nvarguscamera/

vi gstnvarguscamerasrc.cpp

// delete printf in the following lines:

#define GST_ARGUS_PRINT(...)

#define CONSUMER_PRINT(...)

make

sudo make install

You may also use the following line to disable opencv warnings. It is also best to restart nvargus-daemon service each time before using the camera:

import warnings

warnings.filterwarnings('ignore')

import sys, os

os.system("sudo systemctl restart nvargus-daemon")

os.environ["DISPLAY"] = ":0"

os.environ["OPENCV_LOG_LEVEL"] = "OFF"

This will allow you to run your script without any warning messages:



Thursday, February 10, 2022

Install Asterisk 18 / FreePBX 16 on Raspbian Bullseye 64bit/32bit [Raspberry PI 4 aarch64/armhf]

I use this tutorial to setup RemoSIM.com product for customers.

To do:

- Add instructions for enabling fail2ban for asterisk 

- Fix the freepbx startup script issue on boot


I have written about installing Askteris 18 / Free PBX 15 on Ubuntu here before. 

A new version of Raspbian OS based on Debian Bullseye is now available 

Here is the gist I use to install FreePBX 16 on Raspbian Bullseye.

SSH to your raspberry: ssh pi@raspberry.IP.Address 

# Disable ipv6 if it is causing problems in your network:

echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
sysctl -p 

# update packages there 
sudo apt-get update && sudo apt-get dist-upgrade -y

#freepbx installation must be run as root, so login to SSH as root :

sudo passwd
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
service sshd restart

# Install required packages
apt install -y build-essential raspberrypi-kernel-headers apache2 mariadb-server mariadb-client php php-curl php-cli php-mysql php-pear php-gd php-mbstring php-intl php-bcmath curl sox mpg123 lame ffmpeg sqlite3 git unixodbc sudo dirmngr php-ldap nodejs npm pkg-config libicu-dev curl sox libncurses5-dev libssl-dev mpg123 libxml2-dev libnewt-dev sqlite3 libsqlite3-dev pkg-config automake libtool autoconf git unixodbc-dev uuid uuid-dev libasound2-dev libogg-dev libvorbis-dev libicu-dev libcurl4-openssl-dev libical-dev libneon27-dev libsrtp2-dev libspandsp-dev sudo subversion libtool-bin python-dev unixodbc dirmngr sendmail-bin sendmail htop cmake libmariadb-dev-compat nload dnsutils vnstat

#add the following line to [mysqld] section of /etc/mysql/mariadb.conf.d/50-server.cnf
sql_mode=NO_ENGINE_SUBSTITUTION

# restart mariadb
service mariadb restart

# download and install asterisk 18
cd /usr/src
rm -fr asterisk-18-current.tar.gz
wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-18-current.tar.gz
tar xvfz asterisk-18-current.tar.gz
cd asterisk-18.*
contrib/scripts/get_mp3_source.sh
## This line is only needed on rpi 64 bit (arm64)
sed -i contrib/scripts/install_prereq -e "s,i386,armhf,g"
##
contrib/scripts/install_prereq install
./configure --with-pjproject-bundled --with-jansson-bundled
make menuselect.makeopts
menuselect/menuselect --enable app_macro --enable format_mp3 menuselect.makeopts
make
make install
make config
ldconfig
update-rc.d -f asterisk remove

# correct asterisk permissions
useradd -m asterisk
chown asterisk. /var/run/asterisk
chown -R asterisk. /etc/asterisk
chown -R asterisk. /var/{lib,log,spool}/asterisk
chown -R asterisk. /usr/lib/asterisk
rm -rf /var/www/html
mkdir /var/www/html # freepbx reinstall needed

# update apache config
sed -i 's/\(^upload_max_filesize = \).*/\120M/' /etc/php/7.4/apache2/php.ini
sed -i 's/\(^memory_limit = \).*/\1256M/' /etc/php/7.4/apache2/php.ini
sed -i 's/^\(User\|Group\).*/\1 asterisk/' /etc/apache2/apache2.conf
sed -i 's/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf
a2enmod rewrite
systemctl restart apache2

# https://mariadb.com/kb/en/mariadb-connector-odbc/
ver=3.1.17
cd /usr/src
wget https://dlm.mariadb.com/2454036/Connectors/odbc/connector-odbc-$ver/mariadb-connector-odbc-$ver-src.tar.gz
tar -zxvf mariadb-connector-odbc-$ver*
cd mariadb-connector-odbc-$ver*src/
mkdir build
cd build
# RPI 64 bit:
DM_DIR=/usr/lib/aarch64-linux-gnu cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCONC_WITH_UNIT_TESTS=Off -DCMAKE_C_FLAGS_RELWITHDEBINFO="-I/usr/include/mariadb -L/usr/lib"
# RPI 32 bit:
DM_DIR=/usr/lib/arm-linux-gnueabihf cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCONC_WITH_UNIT_TESTS=Off -DCMAKE_C_FLAGS_RELWITHDEBINFO="-I/usr/include/mariadb -L/usr/lib"
##
make
make install

# Configure ODBC

cat <<EOF > /etc/odbcinst.ini
[MySQL]
Description = ODBC for MySQL (MariaDB)
Driver = /usr/local/lib/mariadb/libmaodbc.so
FileUsage = 1
EOF


cat <<EOF > /etc/odbc.ini
[MySQL-asteriskcdrdb]
Description = MySQL connection to 'asteriskcdrdb' database
Driver = MySQL
Server = localhost
Database = asteriskcdrdb
Port = 3306
Socket = /var/run/mysqld/mysqld.sock
Option = 3
EOF

# Download and install freepbx
cd /usr/src
wget http://mirror.freepbx.org/modules/packages/freepbx/freepbx-16.0-latest.tgz
tar vxfz freepbx-16.0-latest.tgz
touch /etc/asterisk/{modules,cdr}.conf
cd freepbx
./start_asterisk start
./install -n
fwconsole ma disablerepo commercial
fwconsole ma install callrecording core dashboard customappsreg infoservices logfiles pm2 soundlang sipsettings voicemail 
fwconsole ma downloadinstall soundlang
fwconsole reload

# Installing chan_dongle
apt-get install usb-modeswitch -y
cd /usr/src
git clone https://github.com/wdoekes/asterisk-chan-dongle
cd asterisk-chan-dongle
./bootstrap
./configure --with-astversion=18.10 --with-asterisk=/usr/src/asterisk-18.10.0/include
make
make install

# chown ttyUSB* devs to asterisk
echo 'KERNEL=="ttyUSB*", GROUP="dialout", OWNER="asterisk"' > /etc/udev/rules.d/50-udev-default.rules

# Freepbx startup script: /etc/systemd/system/freepbx.service
[Unit]
Description=FreePBX VoIP Server
After=mariadb.service
 
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/fwconsole start -q
ExecStop=/usr/sbin/fwconsole stop -q
 
[Install]
WantedBy=multi-user.target

systemctl enable freepbx --now


# Enable swap area on Raspberry 
dd if=/dev/zero of=/swapfile bs=1G count=1
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# add the following line to /etc/fstab
/swapfile swap swap defaults 0 0

delete journald folder so that it stores logs to RAM to avoid high disk io
rm -fr /var/log/journal

# compile atinout command 
cd /usr/src
wget http://sourceforge.net/projects/atinout/files/v0.9.1/atinout-0.9.1.tar.gz
tar -zxvf atinout*.gz
cd atinout-0.9.1
sed -i Makefile -e "s,-Werror,,g"
make
make install
mkdir /scripts


# add this script to send commands to all dongles {0..4} , 4 should be replaced by the number of dongles you have minus one
# vi /scripts/at
#!/bin/bash

dataports=`for i in {0..4}; do asterisk -rx "dongle show device state dongle$i" | grep "Device\|USB" | grep Data | awk '{print $3}'; done`

for data in $dataports; do
echo "$1" | timeout 1 atinout - $data - 2>&1
done

# add this script to remove all sms messages from sim cards / dongles : 
# vi /scripts/deletesms.sh
#!/bin/bash
# Storage types: https://www.developershome.com/sms/cpmsCommand.asp
# Reading commands: https://www.developershome.com/sms/cmgrCommand2.asp
# Delivery reports: https://stackoverflow.com/questions/18251903/how-to-handle-delivery-report-in-gsm-modem
/scripts/at AT+CPMS=\"SR\",\"SR\",\"SR\"
/scripts/at AT+CMGD=1,4
/scripts/at AT+CPMS=\"MT\",\"MT\",\"MT\"
/scripts/at AT+CMGD=1,4
/scripts/at AT+CPMS=\"ME\",\"ME\",\"ME\"
/scripts/at AT+CMGD=1,4
/scripts/at AT+CPMS=\"SM\",\"SM\",\"SM\"
/scripts/at AT+CMGD=1,4

# make them executable
chmod +x /scripts/at
chmod +x /scripts/deletesms.sh

# add deletesms.sh to cronjobs to avoid this bug 
# crontab -e
0 */6 * * * /scripts/deletesms.sh

# Adding a useful alias command: s
# typing s in shell would show status of all dongles with a refresh rate of 1 second:
# vi ~/.bashrc
alias s="watch -n1 'asterisk -rx \"dongle show devices\"'


# add the following cron jobs to keep raspberrypi updated
crontab -e
0 14 * * * apt-get update && apt-get dist-upgrade -y
0 17 * * * /usr/sbin/fwconsole ma refreshsignatures && /usr/sbin/fwconsole ma upgradeall
30 17 * * * /usr/sbin/fwconsole setting SIGNATURECHECK 0
30 17 * * * /usr/sbin/fwconsole setting MODULEADMINEDGE 1
0 18 * * * /usr/bin/rpi-eeprom-update -a

# The following script can be used to monitor your local VPN network (10.0.1.1 here)  and restart the vpn service (wireguard in this example) if the connection was not available. 
# vi /scripts/nointernet.sh
#!/bin/bash
if ping -c 1 10.0.1.1 &> /dev/null
then
  echo 1
else
  echo 0
  /bin/systemctl restart wg-quick@wg0
  /bin/systemctl restart wg-quick@wg1
  sleep 5
  /scripts/tg.py --sender 'System' --dongle 'system' --destination 'system' --message "There was no internet connection, the VPN service was restarted"

fi

# The following scripts can be used to monitor number of dongles you have ( here 5 ) and restart them if they were disconnected
# vi /scripts/down.sh

#!/bin/bash
numdongles=5
downs=$(/usr/sbin/asterisk -rx "dongle show devices" | grep "Not connec\|GSM not\|Unknown" | awk '{print $1}')
now=$(date +'%m-%d-%Y')

# reset down dogles
for down in $downs; do
        /scripts/tg.py --sender 'system' --dongle 'system' --destination 'system' --message "dongle $down was down and it was reset";
        /usr/sbin/asterisk -rx "dongle reset $down";
#        /usr/sbin/asterisk -rx "dongle restart now $down";
done

# need to reset raspberry if all dongles are in Not connected state :
downs=$(/usr/sbin/asterisk -rx "dongle show devices" | grep "Not connec" | awk '{print $1}' | wc -l)
if [ $downs -eq $numdongles ]; then
        /scripts/tg.py --sender 'system' --dongle 'system' --destination 'system' --message "all donlges were down and the pi was restarted";
        /bin/dmesg > /scripts/log/dmesg-$now.txt
        /scripts/restart.sh
fi

# need to reset raspberry if one of dongles is disconnected
notconnected=$(/usr/bin/lsusb | grep Huawei | wc -l)
if [ $notconnected -ne $numdongles ]; then
        /scripts/tg.py --sender 'system' --dongle 'system' --destination 'system' --message "one of dongles was not listed in lsusb and the dongle was restarted";
        /bin/dmesg > /scripts/log/dmesg-$now.txt;
        /scripts/restart.sh
fi

Monday, February 7, 2022

Setting a SAMBA net HDD on Rapberry PI for HIKVision IP Camera IPC-B120


 HIKVision Value Cameras are affordable CCTV cameras that have amazing features such as internal motion detection, IR night vision and power over ethernet (PoE). Among its available products, there are IPC-B121H which has bult-in H.265+ encoding for saving storage, and IPC-B120-D-W which is a wireless camera with Microphone.

The motion detection feature can be used to avoid recording the whole day, and only record when a motion is detected. 

These cameras need a network HDD to store their recordings. It is possible to create such a net HDD using Raspberry. Pi.

Here is an instruction on how to create a SAMBA net HDD using a raspberry pi. Here is another config that is suggested for HikVision cameras however it does not work either. 

The default configuration does not work on HikVision cameras and the camera returns this error when testing the storage:

Mounting to NAS server failed. Invalid directory or incorrect user name/password.

Samba Error hikvision Pi



The reason for this error is explained here . This can be fixed by adding ntlm auth = yes (required since SAMBA v4.5server min protocol = LANMAN1 (required since SAMBA v4.11) to /etc/samba/smb.conf and restarting the samba server.
In addition, it is possible to add log level = 1 to /etc/samba/smb.conf file to enable logging if it still does not work. If it still does not work, compare the output of testparm -v from an old working version of samba with your version.

The following config in /etc/samba/smb.conf is needed for hikvision to work properly:
[parking]
create mask = 0660
force create mode = 0660
force directory mode = 0770
path = /home/pi/parking
read only = No
valid users = @pi
 Note that the connection information in hikvision camera should be entered like this:
Server Address: Raspberry Pi IP
File Path  (note that it must start with /) : /parking
The username and password needs to be created by using smbpasswd .
With this configuration, it works properly
hikvision pi samba working

It is needed to add a separate partition for the camera on the raspberry pi to avoid the camera making the disk space full.

How to Stream RTSP / Webcam / IP Camera Over the Web

I had a Hikvision IPC-B120 that provides a simple RTSP stream, which I could view in VLC. I also wanted to see my Logitech BRIO’s feed in a ...