TimeStamp in mosquitto.log
Monday, September 24. 2018
mosquitto gibt jedem Log-Eintrag einen TimeStamp im für Maschinen recht praktischen Aekunden-seit-Epoche - Format. Für menschliche augen ist diese Angabe eher sperrig.
Mit perl und ccze (macht's bunt) kann man die Ausgabe etwas aufhübschen:
tail -n2000 -f mosquitto/mosquitto.log | perl -pe 's/(\d+)/localtime($1)/e'| ccze -m ansi
Presence Detection in WLAN
Sunday, September 9. 2018
I was not content with the network/pingdevice based presence detection openhab2 offers. While it finds and detects smarphones connect to the wlan, it soon gets beaten by some energy-savong sleep modes, so the device does not ping. It may still respond to arping, though.
The following script is used on a linux router with several interfaces where a device miight be reachable. It can be configured from a settings.ini, reads it's sc an targets from a different ini file and reports it's findings via openHab's REST api.
settings.ini:
[settings]
baseUrl=http://koel.intern:8080/rest/items/
interval=30
interfaces=eth0,eth2
baseUrl points to the REST api of the openHab2 server, interfaces is a comma separated list of the interface/s that should get scanned and interval gives the number of seconds the scanner will sleep between to scans
scan.ini:
[feng]
item=presence_feng
MAC=C0:EE:FB:43:A8:ED
[goldAmmer]
item=presence_goldammer
MAC=192.168.123.11
[ente]
item=presence_ente
MAC=192.168.123.99
Each device has its own section with the section name acting as the unique id of the device, item is the openHab item (expected to be a Switch) that should get the result (ON or OFF) and MAC has the MAC or IP of the device
The scanner is done in python (2.7)
arpscan.py:
#!/usr/bin/env python
#############################
import ConfigParser
import string
import os
import subprocess
import time
import sys
conf={}
devices={}
interfaces=""
scantext=""
grace=3
def get_script_path():
return os.path.dirname(os.path.realpath(sys.argv[0]))
def LoadConfig(file, config={}):
"""
returns a dictionary with keys of the form
<section>.<option> and the corresponding values
"""
config = config.copy( )
cp = ConfigParser.ConfigParser( )
cp.read(file)
for sec in cp.sections( ):
name = string.lower(sec)
obj = { }
for opt in cp.options(sec):
obj[string.lower(opt)] = string.strip(
cp.get(sec, opt))
config[name]=obj
return config
def ScanThings():
scantext=""
for interface in interfaces:
p = subprocess.Popen(["arp-scan","-l","-q","-r","3", "-I", interface], stdout=subprocess.PIPE)
output, err = p.communicate()
scantext += output
for key in devices:
device=devices[key]
url=conf['settings']['baseurl']+device['item']
if device["mac"].lower() in scantext.lower():
print key+" ja"
val = "ON"
device["tap"]=0
else:
print key+" nein"
device["tap"] = device.get("tap", 0) + 1
if device["tap"] <= grace:
print key+" tap: "+str(device["tap"])
val="na"
else:
val="OFF"
if val != "na":
os.system('/usr/bin/curl --silent --header "Content-Type: text/plain" --request POST --data '+val+' '+url)
conf=LoadConfig(get_script_path()+"/"+"settings.ini", conf)
devices=LoadConfig(get_script_path()+"/"+"scan.ini",devices)
interfaces=conf['settings']['interfaces'].split(",")
while 1:
ScanThings()
time.sleep(float(conf['settings']['interval']))
The script is most useful when run as a daemon. You can easily do this with systemd which uses .service files found in /lib/systemd/system/
arpscan.service:
[Unit]
Description=Run arpscan device detection
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/python /usr/local/bin/presence/arpscan.py
Restart=on-abort
[Install]
WantedBy=multi-user.target
The scanner reads settings and scan data, runs an arpscan on each configured interface and finally searches the specified MAC (or IP, just one of the two is needed) in the result.
it needs the linux arp-scan package to be installed, which you can test and confirm by running
arp-scan -l -I eth0
from the commandline. It needs to be run as root.
Some devices may show up oscillating between on and off, to get more stable results the script waits for a number of fails before the "OFF" result is sent. This can be finetuned by the value for grace.