Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c00d755
install grott proxy server
andrewfg Aug 12, 2025
4dbe6e1
typo
andrewfg Aug 12, 2025
83a96dd
use curly braces for string concat
andrewfg Aug 12, 2025
d59d468
download extension python file
andrewfg Aug 12, 2025
ec38803
main menu entries; use username; and determine ip address
andrewfg Aug 13, 2025
5fdbb8c
add DRAFT bats file
andrewfg Aug 13, 2025
c5ce9b1
fix code check suggestion
andrewfg Aug 13, 2025
9d51563
add timestamp; modify .bats
andrewfg Aug 13, 2025
b786fca
tweak test
andrewfg Aug 13, 2025
c2b3233
service start/stop tweaks
andrewfg Aug 13, 2025
d65606f
wip debugging
andrewfg Aug 13, 2025
4b82839
fix global python dependencies
Aug 13, 2025
3b44e9c
add comments
Aug 13, 2025
15396ca
add doc; increase menu size
Aug 13, 2025
43b60b1
refactor based on reviewer suggestions
Aug 14, 2025
6ee008c
change line endings
Aug 14, 2025
f05ce3e
wip
Aug 14, 2025
c851048
refactoring
Aug 14, 2025
cb8c55b
tweak menu sizes
Aug 14, 2025
58c8b7f
use ip address again
Aug 14, 2025
2fc37c8
fix shellcheck error
Aug 15, 2025
833342f
whiptail tweaks
Aug 15, 2025
49e7252
comments cosmetics
Aug 15, 2025
1661e3e
do unattended setup if grottSetupEnabled is true
Aug 16, 2025
43c1d74
fix style check error
Aug 16, 2025
b7cb4c8
fix bats test
Aug 16, 2025
c3b2fa7
fix bats second try
Aug 16, 2025
0c3e52f
prettify logging
Aug 16, 2025
64f3502
tweak to trigger a rebuild
Aug 16, 2025
12624bc
further cosmetics on sequencing and logging
Aug 16, 2025
4d44029
adopt reviewer suggestions
Aug 19, 2025
390cc6c
shorten menu texts
Aug 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build-image/openhabian.conf
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ zram_reset=done # remove when zram is no longer needed to auto update
hotspot=enable
hotspotpw=openhabian

# Grott settings (only enable this if Growatt binding will be used)
# grottSetupEnabled=false

# external SD card device to backup and mirror the internal SD card to
# backupdrive=/dev/sda
storageconfig=openhab-dir
Expand Down
3 changes: 2 additions & 1 deletion docs/openhabian.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,13 @@ Each of these are included as a part of `openhabian-config` menu option 20.
- [OWServer](https://owfs.org) - 1-Wire system of Dallas/Maxim
- [FIND](https://www.internalpositioning.com/) - Framework for Internal Navigation and Discovery
- Mi Flora MQTT daemon
- Grott Proxy server for [Growatt binding](https://www.openhab.org/addons/bindings/growatt/#grott-application-installation-and-setup)

## First boot configuration

Many settings are configurable prior to the first boot of openHABian by changing the key value pairs in the `/boot/openhabian.conf` file on the SD card once you have flashed the initial image onto it.

Please note that - in case you use a Windows system for writing the SD card - the `/boot/` partition will be mounted to a drive named `bootfs`. So, e.g. if this drive has the letter `D:`, `/boot/openhabian.conf` will be found as `D:\openhabian.conf`.
Please note that - in case you use a Windows system for writing the SD card - the `/boot/` partition will be mounted to a drive named `bootfs`. So, e.g. if this drive has the letter `D:`, `/boot/openhabian.conf` will be found as `D:\openhabian.conf`.

The openHABian configuration file uses key value pairs, essentially a list of `option=value` settings in a plain text file.
All supported options are already in the file but unused options and optional components are commented out by default.
Expand Down
20 changes: 12 additions & 8 deletions functions/menu.bash
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ show_main_menu() {
esac

elif [[ "$choice" == "20"* ]]; then
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Optional Components" 24 118 16 --cancel-button Back --ok-button Execute \
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Optional Components (scroll to see more)" 24 118 16 --cancel-button Back --ok-button Execute \
"21 | Log Viewer" "[DEPRECATED] openHAB Log Viewer webapp (frontail)" \
" | Add log to viewer" "[DEPRECATED] Add a custom log to openHAB Log Viewer (frontail)" \
" | Remove log from viewer" "[DEPRECATED] Remove a custom log from openHAB Log Viewer (frontail)" \
Expand All @@ -133,6 +133,8 @@ show_main_menu() {
" | Setup EVCC" "Setup EVCC from command line (German only)" \
"2E | Install ESPHome dashboard" "Deploy ESPHome dashboard" \
" | Remove ESPHome dashboard" "Uninstall ESPHome dashboard" \
"2F | Install Grott" "Install Grott Proxy server (for Growatt binding)" \
" | Remove Grott" "Uninstall Grott Proxy server (for Growatt binding)" \
3>&1 1>&2 2>&3)
RET=$?
if [ $RET -eq 1 ] || [ $RET -eq 255 ]; then return 0; fi
Expand Down Expand Up @@ -160,6 +162,8 @@ show_main_menu() {
*Setup\ EVCC*) setup_evcc;;
2E\ *) install_esphomedashboard "install";;
*Remove\ ESPHome\ dashboard*) install_esphomedashboard "remove";;
2F\ *) install_grott "install";;
*Remove\ Grott*) install_grott "remove";;
"") return 0 ;;
*) whiptail --msgbox "An unsupported option was selected (probably a programming error):\\n \"$choice2\"" 8 80 ;;
esac
Expand Down Expand Up @@ -217,13 +221,13 @@ show_main_menu() {
"42 | Remote Console" "Bind the openHAB SSH console to all external interfaces" \
"43 | Clean cache" "Clean the cache for openHAB" \
"44 | Nginx Proxy" "Setup reverse and forward web proxy" \
"45 | OpenJDK 17" "Install + activate OpenJDK 17 as Java provider (default for OH versions 4 and older)" \
" | OpenJDK 21" "Install + activate OpenJDK 21 as Java provider (DO NOT USE WILL BREAK SYSTEM)" \
" | Temurin 17" "Install + activate Temurin 17 as Java provider (fallback for OH versions 4 and older)" \
" | Temurin 21" "Install + activate Temurin 21 as Java provider (default)" \
" | OpenJDK 11" "Install + activate OpenJDK 11 as Java provider (legacy)" \
"46 | Install openhab-js" "JS Scripting: Upgrade to latest version of openHAB JavaScript library (advanced)" \
" | Uninstall openhab-js" "JS Scripting: Switch back to included version of openHAB JavaScript library" \
"45 | OpenJDK 17" "Setup OpenJDK 17 as Java provider (default for OH v4 and older)" \
" | OpenJDK 21" "Setup OpenJDK 21 as Java provider (DO NOT USE WILL BREAK SYSTEM)" \
" | Temurin 17" "Setup Temurin 17 as Java provider (fallback for OH v4 and older)" \
" | Temurin 21" "Setup Temurin 21 as Java provider (default)" \
" | OpenJDK 11" "Setup OpenJDK 11 as Java provider (legacy)" \
"46 | Install openhab-js" "JS Scripting: Upgrade to latest version of JavaScript library (advanced)" \
" | Uninstall openhab-js" "JS Scripting: Switch back to included version of JavaScript library" \
"47 | Install openhab_rules_tools" "JS Scripting: Manually install openhab_rules_tools (auto-installed)" \
" | Uninstall openhab_rules_tools" "JS Scripting: Uninstall openhab_rules_tools" \
3>&1 1>&2 2>&3)
Expand Down
137 changes: 137 additions & 0 deletions functions/packages.bash
Original file line number Diff line number Diff line change
Expand Up @@ -922,3 +922,140 @@ install_esphomedashboard() {
return
fi
}

## Function for (un)installing Grott proxy server on the current system
## Valid arguments: "install" or "remove"
##
## install_grott(String install|remove)
##
install_grott() {
echo "$(timestamp) [openHABian] Setup Grott proxy... "

# Skip setup if in un-attended mode and openhabian.config grottSetupEnabled is missing or not true
if [[ -n "$UNATTENDED" ]] && [[ "$grottSetupEnabled" != "true" ]]; then
echo "SKIPPED (setup not enabled)"
return 0
fi

# Validate install type argument
if [ "$#" -lt 1 ]; then
echo "FAILED (missing install type - usage: $0 <install|remove>)"
return 1
elif [[ "$1" != "install" && "$1" != "remove" ]]; then
echo "FAILED (invalid install type $1 - usage: $0 <install|remove>)"
return 1
fi
local installType="$1"

# Constants for local system
local grottFolder="/home/${username:-openhabian}/grott"
local iniName="grott.ini"
local serviceName="grott.service"
local iniFile="${grottFolder}/${iniName}"
local serviceFile="/etc/systemd/system/${serviceName}"
local iniTemplate="${BASEDIR:-/opt/openhabian}/includes/${iniName}"
local serviceTemplate="${BASEDIR:-/opt/openhabian}/includes/${serviceName}"
local runScript="grott.py"

# Constants for Grott GitHub files
local grottSourceUrl="https://raw.githubusercontent.com/johanmeijer/grott/master"
local grottSourceFiles=(
"grott.py"
"grottconf.py"
"grottdata.py"
"grottproxy.py"
"grottserver.py"
"grottsniffer.py"
)
local grottExtUrl="${grottSourceUrl}/examples/Extensions"
local grottExtFile="grottext.py"

## Install Grott proxy
if [[ $installType == "install" ]]; then
echo "$(timestamp) [openHABian] Installing Grott proxy... "

# Get default IPv4 address
local ipAddress
ipAddress="$(ip route get 8.8.8.8 | awk '{print $7}' | xargs)"
if ! [[ "$ipAddress" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "FAILED (invalid ip address ${ipAddress})"
return 1
fi
local extUrl="http://${ipAddress}:8080/growatt"

# Update system and install dependencies. NOTE: paho-mqtt is a required dependency (even if disabled)
if ! cond_redirect apt-get update; then echo "FAILED (apt update)"; return 1; fi
if ! cond_redirect apt-get install --yes -o DPkg::Lock::Timeout="$APTTIMEOUT" python3 python3-pip python3-paho-mqtt python3-requests; then echo "FAILED (install Python or dependencies)"; return 1; fi

# Prepare Grott folder
if ! cond_redirect mkdir -p "$grottFolder"; then echo "FAILED (create ${grottFolder})"; return 1; fi
if ! cond_redirect chown -R "${username:-openhabian}" "$grottFolder"; then echo "FAILED (chown ${grottFolder})"; return 1; fi
if ! cond_redirect chmod -R 755 "$grottFolder"; then echo "FAILED (chmod ${grottFolder})"; return 1; fi

# Download Grott Python files into Grott folder
local src tgt
for file in "${grottSourceFiles[@]}"; do
src="${grottSourceUrl}/${file}"
tgt="${grottFolder}/${file}"
curl -fsSL "${src}" -o "${tgt}" || {
echo "FAILED (download ${file})"
return 1
}
done

# Download Grott extension file into Grott folder
src="${grottExtUrl}/${grottExtFile}"
tgt="${grottFolder}/${grottExtFile}"
curl -fsSL "${src}" -o "${tgt}" || {
echo "FAILED (download ${grottExtFile})"
return 1
}

# Create grott.ini configuration in Grott folder by modifying the template
if ! sed \
-e "s|%URL|$extUrl|g" \
"$iniTemplate" > "$iniFile"; then
echo "FAILED (configure ${iniName})"
return 1
fi

# Create grott.service configuration in systemd folder by modifying the template
if ! sed \
-e "s|%USERNAME|${username:-openhabian}|g" \
-e "s|%DIRECTORY|$grottFolder|g" \
-e "s|%RUNSCRIPT|$runScript|g" \
"$serviceTemplate" > "$serviceFile"; then
echo "FAILED (configure ${serviceName})"
return 1
fi

# Enable and start Grott service
if ! cond_redirect systemctl enable --now "${serviceName}"; then echo "FAILED (enable ${serviceName})"; return 1; fi

if [[ -n "$INTERACTIVE" ]]; then
whiptail --title "Grott Proxy Installed" --msgbox "We installed Grott proxy on your system." 7 80
fi
fi

## Remove Grott proxy
if [[ $installType == "remove" ]]; then
echo "$(timestamp) [openHABian] Removing Grott Proxy... "

# Stop and disable systemd service
if ! cond_redirect systemctl disable --now "${serviceName}"; then echo "FAILED (disable ${serviceName})"; return 1; fi
cond_redirect systemctl daemon-reload

# Remove systemd service file
if ! cond_redirect rm -f "$serviceFile"; then echo "FAILED (remove ${serviceFile})"; return 1; fi

# Remove Grott folder
if ! cond_redirect rm -rf "$grottFolder"; then echo "FAILED (remove ${grottFolder})"; return 1; fi

if [[ -n "$INTERACTIVE" ]]; then
whiptail --title "Grott Proxy Removed" --msgbox "We removed Grott proxy from your system." 7 80
fi
fi

Comment thread
andrewfg marked this conversation as resolved.
echo "OK"
return 0
}
17 changes: 17 additions & 0 deletions functions/packages.bats
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ teardown_file() {
unset BASEDIR
systemctl kill homegear.service || true
systemctl kill mosquitto.service || true
systemctl kill grott.service || true
}

@test "destructive-homegear_install" {
Expand Down Expand Up @@ -64,3 +65,19 @@ teardown_file() {
[ "$status" -eq 0 ]
echo -e "# ${COL_GREEN}$(timestamp) [openHABian] 1wire installation successful.${COL_DEF}" >&3
}

@test "destructive-grott_install" {
## Confirm Grott Proxy install completes without error
echo -e "# ${COL_CYAN}$(timestamp) [openHABian] Grott Proxy installation starting...${COL_DEF}" >&3
run install_grott "install" 3>&-
if [ "$status" -ne 0 ]; then echo "$output" >&3; fi
[ "$status" -eq 0 ]
echo -e "# ${COL_GREEN}$(timestamp) [openHABian] Grott Proxy installation successful.${COL_DEF}" >&3

## Confirm Grott service is running
echo -e "# ${COL_CYAN}$(timestamp) [openHABian] Checking if Grott Proxy service is running...${COL_DEF}" >&3
run systemctl is-active --quiet grott
if [ "$status" -ne 0 ]; then echo "$output" >&3; fi
[ "$status" -eq 0 ]
echo -e "# ${COL_GREEN}$(timestamp) [openHABian] Grott Proxy service is running.${COL_DEF}" >&3
}
107 changes: 107 additions & 0 deletions includes/grott.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Specify grott monitor configuration
# Defaults are described
# Remove # and update the value to enable the setting
# Last updated: 2022-11-04
# Version 2.7.0

[Generic]
# Specify verbose for extended messaging
verbose = True

# Specify minrecl for debugging purposes only (default = 100)
#minrecl = 100

# Specify mode (sniff or proxy)(> 2.1.0 proxy is default)
mode = proxy

# Specify port and IP address to listen to (only proxy), default port 5279, 0.0.0.0 ==> own ip address
ip = default
port = 5279

# To blocks commands from outside (to channge inverter and shine devices settings) specify blockcmd = True,
# Specify noipf = True if you still want be able to set the destination ip addres from growatt server (advice
# only to use this for a short time)
#blockcmd = True
#noipf = True

# Time = auto/server parameter enable/disable date/time retrieval from data record (server), default is
# auto: grott decides which time is used (data record if valid otherwise Server)
# If time = server Grott server time is alwas used
#time = auto

# Sendbuf = True / False parameter to enable / disable sending historical (buffered) data. Default is sendbuf = True.
#sendbuf = True

# Compat is True and valoffset needs to be set if offset / growatt protocol has been changed.
compat = False
#valueoffset = 6

# Specify inverter id (not necessary in version >2.1.0 if compat = false!)
#inverterid = KUM0CLU03Y
# Specify the type of the inverter (default/sph/spf/max)
invtype = sph

# Decrypt is False if growatt communication is not encrypted (older inverters), (not necessary in version
# >2.1.0 if compat = false!)
#decrypt = True

[Growatt]
# Server name/IP address and port of Growatt server
# specify only if the IP address of server.growatt.com is changed
# The address as of Nov 2022 is 47.91.67.66

ip = server.growatt.com
#ip = 47.91.67.66
#port = 5279

[MQTT]
# Mqtt parameters definitions
# Be aware nomqtt = True means no MQTT processing will be done!!!!!!

nomqtt = True
#ip = localhost
#port = 1883
#topic= energy/growatt
#auth = False
#user = grott
#password = growatt2020

[PVOutput]
# PVOutput parameters definitions

pvoutput = False
#apikey = yourapikey
# Data upload limit (in minutes)
#pvuplimit = 5
# Use this if you have one inverter
#systemid = 12345

# Use this if you have multiple inverters
#pvinverters = 2
#systemid1 = 12345
#inverterid1 = inverter1
#systemid2 = 67890
#inverterid2 = inverter2

#systemid99 = 99999
#inverterid99 = inverter99

[influx]
# Influxdb parameters definitions

#influx = False
#influx2 = False
#dbname = grottdb
#ip = localhost
#port = 8086
#user = grott
#password = growatt2020
#token = "influx_token"
#org = "grottorg"
#bucket = "grottdb"

[extension]
# grott extension parameters definitions
extension = True
extname = grottext
extvar = {"url": "%URL"}
13 changes: 13 additions & 0 deletions includes/grott.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Grott Proxy Service
After=network.target

[Service]
SyslogIdentifier=grott
User=%USERNAME
WorkingDirectory=%DIRECTORY
ExecStart=-/usr/bin/python3 -u %DIRECTORY/%RUNSCRIPT
Restart=on-failure

[Install]
WantedBy=multi-user.target
1 change: 1 addition & 0 deletions openhabian-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ if [[ -n "$UNATTENDED" ]]; then
zram_setup
exim_setup
nut_setup
install_grott "install"
permissions_corrections
setup_mirror_SD "install"
install_cleanup
Expand Down