Notifications to PC with Snarl

From Domoticz
Jump to: navigation, search


Domoticz supports notifications to mobile devices with Pushover, Pushsafer and Prowl. A good notification system to the PC desktop was missing because I do not carry the mobile phone at all times. Pushover can push messages to the desktop but this only works in a browser. Pushsafer can send messages with an image to iOS, Android and Windows 10 (Phone & Desktop).

When searching for notification receivers I found Snarl which is a great notification system for events like low diskspace, IM events, played music, time, anything you can think of! Only the link from Domoticz to Snarl was missing but in a few hours the author of Snarl popped out a Python script that connects to Snarl from the Pi.


Get the Snarl installer here: Download Snarl-3.1-setup.exe (9.9 MB).

It is also possible to get Snarl notifying on OSX or Linux.

Make sure to allow traffic to Snarl listening on port 9887 in your desktop firewall.

Then get the Python script here: Download (3.8 KB) .

Copy to /home/pi/domoticz/scripts, you can use WinSCP for that.

On the Domoticz Pi, make sure you have Python3 installed. The command Python3 will give an error when it is not present or enter Python3 (ctrl-D to leave). This command will install Python3:

sudo apt-get install python3

About 30MB diskspace is used totally.

Now you can fire your first test command:

python3 -d -b 'Hello, world' -i '!system-info' -n '!windowslogon' -s
snp-send: connecting to!
snp-send: notification sent

Change the IP address to your desktop's IP. All possible command options are explained in the Readme in the downloaded If all went well, you will see a text message Hello, world with an icon and a sound and see two messages on the Pi command line.

Now create a new bash script, or add a line to your existing Pushover notification script in /home/pi/domoticz/scripts:


snp-send: notification sent
/usr/bin/python3.2mu /home/pi/domoticz/scripts/ -d -b 'Hello, world!' -i '!system-yes' -n 'd:\shared\fluitje.mp3'

Change the IP address to your desktop's, and change or remove the sound option (-n). I borrowed the railway station bell sound from the NS app here :-) Save the file with ctrl+X. Then make it executable:

chmod +x

In Domoticz - Switches, edit the switch you want to make notifications. Put this in field On Action:


If all went well, when you toggle the switch to on (or an event does this), then you will see a notification from Snarl on your desktop!

When the desktop is down or Snarl is not running, a message in the Domoticz log is written:

Thu Feb 5 08:12:48 2015 Error: Error executing script command (home/pi/domoticz/scripts/ returned: 512

Other Stuff

I snatched the Domoticz icon from the website and copied it to the Snarl default icon folder: C:\Program Files\Snarl\etc\default_theme\icons

Direct link to the icon picture.

python3.2 -d -b 'Door 2 open for 5 minutes' -i '!domoticz-icon' -n 'd:\shared\fluitje.mp3'

Snarl notification on desktop

Snarl notification on desktop

Python code

Here is the Python 3.2 script for the Raspberry Pi. Just copy it here or get the file here. This is version 0.5.

# -- multi-platform Snarl notification sender
# Copyright (C) 2015 full phat products
BUILD_VER = "0.5"
# Change log:
# 0.5 - Even more Python 3.2 friendly
# 0.4 - Modified socket exception handling to work better on Python 3.2
# 0.3 - No longer dependent on ipaddress module
# 0.2 - Added sticky, priority and callback options
#       Better option handling  
#       More robust packet building
#       Validates IP address using ipaddress module
# 0.1 - initial version
    import ipaddress
except ImportError:
import socket
import getopt
import sys
#import os
class term:
   PURPLE = '\033[95m'
   CYAN = '\033[96m'
   DARKCYAN = '\033[36m'
   BLUE = '\033[94m'
   GREEN = '\033[92m'
   YELLOW = '\033[93m'
   RED = '\033[91m'
   BOLD = '\033[1m'
   UNDERLINE = '\033[4m'
   END = '\033[0m'
destport = 9887
destip = ""
content = ''
priority = 0
debugmode = False
copyright = term.BOLD + "\nsnp-send " + BUILD_VER + "\n"  + term.END + \
            "Copyright (c) 2015 full phat products"
usage = "usage: snp-send " \
        "[-b body] [-c callback] [-d ip] [-i icon] [-n sound] " \
        "[-p port] [-r priority] [-s] [-t title] \n"
hint =  "" \
        "  -b    Notification body\n" \
        "  -c    Callback URL, !bang command or @signal\n" \
        "  -d    Destination IP address (default is\n" \
        "  -i    Url, !system icon or UNC path to image file\n" \
        "  -n    Sound to play\n" \
        "  -p    Destination TCP port (default is 9887)\n" \
        "  -r    Notification priority.  Must be between -2 and +2.  Default is 0\n" \
        "  -s    Requests notification to be displayed sticky (infinite duration)\n" \
        "  -t    Notification title\n" \
        "\n" \
        "Notes\n" \
        "  - At least one of title, body or icon must be supplied.\n"
#        "  - At least one of " + term.BOLD + "title" + term.END +", " + term.BOLD + "body" + term.END + " or " + term.BOLD + "icon" + term.END + " must be supplied.\n"
if len(sys.argv) < 2:
    print('snp-send: arg missing')
    opts, args = getopt.getopt(sys.argv[1:], "b:c:d:i:n:p:r:st:?", ["body=", "debug", "sticky", "title="])
except getopt.GetoptError:
    print('snp-send: arg missing')
for o, a in opts:
    if o == "-d":
        destip = a
    elif o == "-p":
            destport = int(a)
        except ValueError:
            print('snp-send: port must be an intger between 0 and 65535')
    elif o in ("-t", "--title"):
        content = content + 'title=' + a + '&'
    elif o in ("-b", "--body"):
        content = content + 'text=' + a + '&'
    elif o == "-c":
        content = content + 'callback=' + a + '&'
    elif o == "-i":
        content = content + 'icon=' + a + '&'
    elif o == "-n":
        content = content + 'sound=' + a + '&'
    elif o == "-r":
        # priority
            priority = int(a)
        except ValueError:
            print('snp-send: priority must be an intger between -2 and 2')
        if priority != 0:
            content = content + 'priority=' + a + '&'
    elif o in ("-s", "--sticky"):
        content = content + 'duration=0&'
    elif o == "-?":
    elif o == "--debug":
        debugmode = True
# validate args
except ValueError:
    print('snp-send: invalid destination IP address')
except NameError:
# construct the SNP/3.0 packet
packet = 'SNP/3.0\r\nnotify?'
# add rightstr(content, len(content) -1 )
packet = packet + content[:-1] + '\r\n'
if debugmode:
    print("content:\n" + content)
# TO-DO: add headers
# add footer
packet = packet + 'END\r\n'
if debugmode:
    print("packet:\n" + packet)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('snp-send: connecting to ' + destip + ':' + str(destport) + '...', end = '')
    s.connect((destip, destport))
except socket.error as e:
    print('failed (' + str(e) + ')')
    s.send(bytes(packet, 'UTF-8'))
    print('snp-send: notification sent')
    data = s.recv(1024)