Install script for Domoticz with open-zwave driver in iocage jail

tfjad

Dabbler
Joined
Nov 1, 2016
Messages
12
A friend of mine, who is into home automation, wanted to install the domoticz system with drivers for the Aeotec Z-Stick Z-Wave USB stick into FreeNAS 11.1. I took as a challenge to find out, how difficult would it be to write a fairly complex, but fully automatic installation script of a FreeNAS jail.

This script is based on the wiki article at https://www.domoticz.com/wiki/FreeNAS
Also, man iocage and the FreeBSD iocage documentation at https://www.freebsd.org/cgi/man.cgi?query=iocage&sektion=8 are great resources.

This was originally done for a warden jail. The code that has to do with devfs rules was necessary there, but now that this script creates the domoticz jail in iocage, some of that code is superfluous. Also, some other services are installed in my friend's domoticz jail, so some settings in this script are not necessary just for domoticz.

The jail needs access to the Z-Wave USB device /dev/cuaU0 in the host system. In the iocage jail I could not access this device until I set devfs_ruleset=0. This basically gives the jail potentially access to everything in the host's /dev. I think the correct way would be to give access to only those devices that the jail really needs access to. I just couldn't figure out the correct devfs settings. Feel free to experiment with the iocage jail settings.

At the start of the script you will find some settings, which you should set before running the script.

JAIL_IP is the ip4_addr property. That is, the interface name and the ipv4 address and netmask you want to give for the jail. You can use e.g. vnet0 for the interface. If the start of this string is "vnet", the script will set vnet=on for the jail automatically. Note: to use vnet in iocage, you may need to set some tunables in FreeNAS. You can find many threads about that topic on this forum.

DEFAULT_ROUTER is the default router's ipv4 address.

For DOMOTICZ_DB_DIR you may enter a directory or a dataset on the FreeNAS side to be used as the database directory for domoticz. If this directory does not exist when you run this script, then this setting will not be applied, and domoticz will have it's database only in /var/db/domoticz/ in the jail.

If AUTOBOOT=1, then the script will set boot=on for the jail. If AUTOBOOT=0, then the boot property will not be set.

That's all you need to do. When you start the script, everything will be automatic. It takes about 15 minutes for the script to do this installation in my Freenas 11.1 VM. When the script has finished, it will show you the URL to access domoticz. Note: if domoticz seems unresponsive, turn off adblocking in your browser.

Obviously, this installation is of little use, if you don't have the Z-Wave USB stick or any other compatible device. You can still install domoticz, but there isn't much to to do in domoticz, if you don't have any hardware to play with.

With this script I want to show that it is quite possible to write "one click" installation scripts for iocage jails in FreeNAS 11.1.

To undo everything this script does, just type
iocage destroy domoticz
and delete user "domoticz" and group "domoticz" from FreeNAS.

The code is just ONE script file.
Code:
#!/bin/bash

# Network settings:
JAIL_IP="em0|192.168.0.102/24"
DEFAULT_ROUTER="192.168.0.1"

# Domoticz database directory in the host. Set to "" if you don't want to use this feature:
DOMOTICZ_DB_DIR="/mnt/Volume1/db/domoticz"
AUTOBOOT=1
############################################################################################################

if [ "$(id -u)" != "$(id -u root)" ]; then
	# could do:
	# eval "sudo $0"
	echo "You must be root to run this installer."
	exit 1
fi

show_msg() {
	echo "**************************************************************"
	echo "*"
	while (( "$#" )); do
		echo "* $1"
		shift
	done
	echo "*"
	echo "**************************************************************"
}

fn="$(basename $0)"
TMPFILE="$(mktemp -q '/tmp/'"$fn"'.XXXX')"
[ -e $TMPFILE ] || exit 1

# Detect or create user domoticz in the host
DOMOTICZ_UID="$(id -u domoticz)"
if [ -z "$DOMOTICZ_UID" ]; then
   pw useradd -q -n domoticz -s /sbin/nologin -h -
   DOMOTICZ_UID="$(id -u domoticz)"
fi
DOMOTICZ_GID="$(id -g domoticz)"

# Detect Z-Wave device and set /etc/devfs.rules
addr="$(dmesg | sed -rn 's/.*umodem.*addr ([0-9]+).*/\1/p' | tail -n 1)"
if [ -n "$addr" ]; then
	if [ -n "$(grep 'devfsrules_jail_allow_usb' /etc/devfs.rules)" ]; then
		sed -r "s/(devfsrules_jail_allow_usb=)([0-9]+)/\1${addr}/" /etc/devfs.rules >$TMPFILE
		mv -f $TMPFILE /etc/devfs.rules
	else
		echo "[devfsrules_jail_allow_usb=${addr}]" >> /etc/devfs.rules
		echo "add path 'cu*' unhide" >> /etc/devfs.rules
	fi
fi

JROOT="$(jls | awk '$3 ~ /domoticz/ {print $4}')"
if [ -z "$JROOT" ]; then
	show_msg "Creating domoticz jail..."
	printf '{ "pkgs": [ "python3", "openssl", "sqlite3", "expat", "curl", "libiconv", ' >$TMPFILE
	printf '"gmake", "cmake", "subversion", "git", "devel/boost-libs", ' >> $TMPFILE
	printf '"devel/boost-python-libs", "devel/boost-all" ]}' >> $TMPFILE
	VNET=""
	[ "${JAIL_IP:0:4}" == "vnet" ] && VNET="vnet=on"
	BOOTFLAG=""
	[ $AUTOBOOT -ne 0 ] && BOOTFLAG="boot=on"
	iocage create -n "domoticz" -r 11.1-RELEASE -p $TMPFILE ip4_addr="$JAIL_IP" \
		   defaultrouter="$DEFAULT_ROUTER" $VNET allow_raw_sockets="1" $BOOTFLAG
	[ $? -eq 0 ] || exit 1
	iocage set allow_mount="1" allow_mount_devfs="1" enforce_statfs="1" domoticz
	iocage set mount_devfs="1" allow_mount_nullfs="1" allow_mount_tmpfs="1" domoticz
	iocage set devfs_ruleset="0" domoticz

	JROOT="$(jls | awk '$3 ~ /domoticz/ {print $4}')"	
	sed '1,/--divider--$/d' "$0" > $TMPFILE
	[ -s "$TMPFILE" ] && dbdir="$(sed -rn 's/.*_dbdir:=(\/.*)}.*/\1/p' $TMPFILE)"
	[ -n "$dbdir" ] || dbdir="/var/db/domoticz"
	if [ "$(iocage get state domoticz)" != "up" ]; then
		iocage start domoticz &> /dev/null
		if [ $? -ne 0 ]; then
			show_msg "Error: The domoticz jail has been created," "but it does not start."
			exit 1
		fi
	fi

	# Build the domoticz jail
	cat << EOF | iocage chroot domoticz
	pw groupadd -n domoticz -g $DOMOTICZ_GID
	pw useradd -n domoticz -u $DOMOTICZ_UID -g $DOMOTICZ_GID -m -s /sbin/nologin -h -
	pw groupmod dialer -m domoticz
	git clone https://github.com/OpenZWave/open-zwave.git /home/domoticz/open-zwave-read-only
	gmake -C /home/domoticz/open-zwave-read-only
	git clone https://github.com/domoticz/domoticz.git /home/domoticz/domoticz
	cmake -DCMAKE_BUILD_TYPE=Release /home/domoticz/domoticz/CMakeLists.txt
	make -j 2 -C /home/domoticz/domoticz
	chown -R domoticz:domoticz /home/domoticz/domoticz
	[ ! -d "$dbdir" ] && mkdir -p "$dbdir"
	chown domoticz: "$dbdir"
	mkdir /var/run/domoticz
	chown :domoticz /var/run/domoticz
	chmod 770 /var/run/domoticz
	echo "" >>/etc/rc.conf
	echo "# Lines added by domoticz" >> /etc/rc.conf
	echo 'hostname="domoticz"' >> /etc/rc.conf
	echo 'devfs_enable="YES"' >> /etc/rc.conf
	echo 'devfs_system_ruleset="devfsrules_common"' >> /etc/rc.conf
	echo 'domoticz_enable="YES"' >> /etc/rc.conf
EOF
	if [ -d "$DOMOTICZ_DB_DIR" ]; then
		iocage fstab -a domoticz "$DOMOTICZ_DB_DIR"  "$dbdir"  nullfs  rw  0  0
	else
		show_msg "Warning: Database directory not outside of the jail."
	fi
fi

# Trying to install the domoticz service in the jail
if [ ! -s $TMPFILE ]; then
	sed '1,/--divider--$/d' "$0" > $TMPFILE
fi
if [ -s $TMPFILE ]; then
	cp -f $TMPFILE "${JROOT}/etc/rc.d/domoticz"
	chmod 555 "${JROOT}/etc/rc.d/domoticz"
fi

if [ $AUTOBOOT -eq 0 ]; then
	iocage stop domoticz &> /dev/null
else
	iocage restart domoticz &> /dev/null
fi

# Creating the ttyUSB# device(es) and setting permissions
for cua in $(ls /dev/cuaU* 2>/dev/null); do
	ln -sf "$cua" "${JROOT}/dev/ttyUSB${cua: -1}"
done
chown root:domoticz "${JROOT}/dev/ttyU"* &> /dev/null
chmod 660 "${JROOT}/dev/ttyU"* &> /dev/null

domoip="$(jls | awk '$3 ~ /domoticz/ {print $2}')"
if [ "$(iocage get state domoticz)" == "up" ]; then
	show_msg "Domoticz is now running." "" \
	"The web user interface is at:" "" "http://$domoip:8080"
else
	show_msg "Domoticz is now installed. Start it from" \
		"the FreeNAS new UI Jails section," \
		"or by running:" "" "iocage start domoticz" "" \
		"The web user interface will be at:" "http://$domoip:8080"
fi
rm "$TMPFILE" &> /dev/null
exit 0

# Do not remove or alter the divider line below!
# --divider--
#! /bin/sh
#
#

# PROVIDE: domoticz
# REQUIRE: LOGIN cleanvar
# KEYWORD: shutdown

#
# Add the following lines to /etc/rc.conf to enable domoticz:
#
#domoticz_enable (bool): set to "YES" to start domotics at boot
#domoticz_dbdir (str):   Default to "/var/db/domoticz"
#						domoticz database directory
#domoticz_user (str):	Default to www, user for starting domoticz
#domoticz_group (str):   Default to www, group for stating domoticz
#domoticz_pidfile (str): Custum PID file path and name
#						Default to "/var/run/domoticz/${hostname}.pid".
#domoticz_args (str):	Custom additional arguments to be passed
#

. /etc/rc.subr

name="domoticz"
rcvar="domoticz_enable"
stop_cmd="${name}_stop"

load_rc_config $name

: ${domoticz_dbdir:=/var/db/domoticz}
: ${domoticz_user:=domoticz}
: ${domoticz_group:=domoticz}
: ${domoticz_enable:=no}
: ${domoticz_directory:="/home/domoticz/domoticz/"}
: ${domoticz_args:="-syslog -daemon"}

pidfile=${domoticz_pidfile:-"/var/run/domoticz/${hostname}.pid"}

command="/home/domoticz/domoticz/domoticz"
command_args="-dbase ${domoticz_dbdir}/domoticz.db -pidfile ${pidfile} ${domoticz_args}"

domoticz_stop() {
		if [ -e "${pidfile}" ]; then
				echo "Stopping ${name}..."
				kill -9 `cat ${pidfile}`
				rm ${pidfile}
		fi
}

run_rc_command "$1"

edit: simplified code by removing unnecessary sed usage
 
Last edited:

iguaan

Cadet
Joined
Oct 9, 2017
Messages
2
Hello,
i've managed to install and run domo in warden for a few years now. And also updated it by the knowledge i've gathered using google. It's currently still running in warden, but i've upgraded to 11.2 and tried to install a new instance to iocage, but have problems runnig your script.
I know for sure that the problem is in the lack of my knowledge, which is based on google.
I created a new jail (domo) and when i edited the script to my needs (set the ip and new uid/guid name) i've got following when i ran script:
Code:
root@domo:/ # /bin/sh domo_inst.sh
id: domoticz2: no such user
id: domoticz2: no such user
id: domoticz2: no such user
**************************************************************
*
domo_inst.sh: 1: not found
*
**************************************************************
domo_inst.sh: ${JAIL_IP:0...}: Bad substitution
 

Grimmie

Cadet
Joined
Mar 22, 2020
Messages
8
Sorry for replying to an old topic, but I can't seem to find any more up to date info on this matter anywhere.

I am trying to install Domoticz on my Freenas server (11.2 U8). Obviously this cannot be done the old way with a warden jail. I'll have to use iocage.

I'm sure I'm not doing this right or am missing some crucial steps.
But if I SSH into my Freenas with Putty and try to run your script, nothing happens.

Sorry for my lack of knowledge, I used to be able to create jails just fine (with the help of Google) in the FreeNas 9.x era. But now I'm lost.

Hope someone can point me in the right direction if there are any stepts that need to be done before running the script.
 

Grimmie

Cadet
Joined
Mar 22, 2020
Messages
8
Hmm.... got as far as running the script now.
"11.1-Release was not found!"

I guess thats the end of that :(
 

Grimmie

Cadet
Joined
Mar 22, 2020
Messages
8
Ok... had that fixed by editing the script where it says:
iocage create -n "domoticz" -r 11.1-RELEASE -p $TMPFILE ip4_addr="$JAIL_IP" \
to
iocage create -n "domoticz" -r 11.2-RELEASE -p $TMPFILE ip4_addr="$JAIL_IP" \

Next error pops up:
ifconfig: interface em0 does not exist

I assume that refers to:
#!/bin/bash

# Network settings:
JAIL_IP="em0|192.168.0.102/24"
DEFAULT_ROUTER="192.168.0.1"

My interface for freenas is configured as re0, should I change the script to re0, or will I break things?
 

Attachments

  • Knipsel.JPG
    Knipsel.JPG
    19.4 KB · Views: 624

Grimmie

Cadet
Joined
Mar 22, 2020
Messages
8
OK... having a conversation with myself :)

Reading helps!

Over here: https://www.freebsd.org/cgi/man.cgi?query=iocage&sektion=8 I read the following:
On shared IP jails, an interface name given before the IP
address adds an alias to that interface. If the DEFAULT
keyword is given instead of an interface name, the inter-
face is automatically assigned based on the system's de-
fault interface.

Now the script ran all the way and I was greeted with the message that install was succesfull and domoticz could be found at 192.168.1.102:8080.

HOWEVER... When I type that into my browser, I get into Freenas, not Domoticz... I'm guessing the interface name has got something to do with that...?

Time for more research...
 

Grimmie

Cadet
Joined
Mar 22, 2020
Messages
8
Searching and reading some more I came across this: https://iocage.readthedocs.io/en/latest/networking.html

Now I'm at a loss...
Reading the above I think VNET is what I want?
If I look at the script, VNET = on.
What am I missing? Why do I end up with my FreeNas loginscreen instead of domoticz when I enter the configured IP.
Any help appreciated.
 

hervon

Patron
Joined
Apr 23, 2012
Messages
353
I had a vnet issue. I solved it by leaving the "interface name" blank in the jail configuration.
 

Grimmie

Cadet
Joined
Mar 22, 2020
Messages
8
Final addition for the day.
# iocage get vnet domoticz, teaches me that VNET = off, which is strange because in the script I clearly see VNET = on.

But anyway, now I'm even more confused, I assume I should follow these steps: https://iocage.readthedocs.io/en/latest/networking.html#vimage-vnet
But I'm clueless how that works, perhaps something for another day... unless someone has some good pointers for me.
 

Grimmie

Cadet
Joined
Mar 22, 2020
Messages
8
I had a vnet issue. I solved it by leaving the "interface name" blank in the jail configuration.
Thanks for the hint, unfortunately no dice...
Installs fine, but loops back to my Freenas login screen just as well.
 

hervon

Patron
Joined
Apr 23, 2012
Messages
353
You chose a different IP for the jail than FreeNAS as requested ?
 

hervon

Patron
Joined
Apr 23, 2012
Messages
353
Guess : check network (or system) setting to make sure only 192.168.1.5 allows to reach FreeNAS (and there are no aliases)

You could try another Jail IP just in case.
 
Top