TRC270F – KNX Tussenstekker

TRC270F

Hager TRC270F – draadloos knx 230v relais

 

Nu ik eindelijk dacht dat KNX geen geheimen meer had voor mij kwam ik toch wel vast te zitten bij het configureren van een nieuwe draadloze knx relais. Bovenstaande tussenstekker schakelt een belasting op 230v.

Vol goede moed voegde ik dit toestel toe op mijn RF lijn van mijn ETS project. Als 5de draadloze busdeelnemer.

Even een refresh: Een draadloze lijn voor de hager mediacoupler onder te brengen gebeurt niet op een RF lijn maar op een TP lijn. Verder wordt er als eerste device dan een Hager Media Coupler geplaatst welke .0 als busdeelnemer adres heeft.

2019-06-18 12_54_58-Calculator

Nieuwe groepsadressen aanmaken en koppelen

trc270_groupsaddresses

Nadien volgt het starten van de configuratieplugin (openen onder de parameter tab van 1.2.0 Media coupler)

Hier ging alles heel vlot:

  1. Onder physical addressing het nieuwe toestel zoeken. Aangezien deze de fabrieksinstellingen had kwam de nieuwe TRC270 automatisch in de lijst.
  2. Fix address procedure uitvoeren
  3. Download van parameters uitvoeren
  4. Physical effect testen ==> OK

2019-06-18 12_58_24-Photos

Alles werkte perfect en ik dacht dat ik na een kwartiertje werk reeds klaar was.

Toen ik het toestel in productie bracht kwam ik tot de vaststelling dat er niets gebeurde!

Al snel keek ik via de busmonitor en zag dat er geen telegrammen van de nieuwe TCR270 op de bus terechtkwamen.

Na contact met support van Hager bleek er een filtering op de groepsadressen aanwezig te zijn. Wanneer er een nieuw groepsadres aangemaakt wordt kan deze standaard niet tussen verschillende lijnen communiceren. (Filtered)

De oplossing was op het niveau van de groepsadressen een parameter aan te passen zodat de groepsadressen van de TRC270 weldegelijk tussen verschillende lijnen mag communiceren.

filtered_addresses

(Of in het Engels Pass through line coupler) aanvinken en nadien de download opnieuw uitvoeren via de media coupler plugin.

De enige vraag dat nog openstaat is waarom mijn draadloze afstandsbedieningen (Hager TU402) en draadloze rookmelders (Hager TGA510A) wel kunnen communiceren. (Zonder niet filteren aan te zetten!) Ik gebruik deze KNX componenten reeds enkele jaren en doen het perfect.

Watermeter

Gebruikte materialen

Arcus-EDS
KNX-GW-MBUS REG

arcus_60400002-1

Maddalena FlowPulse M-Bus Counter

27_m-bus_mvm_1476444198

Analoge watermeter

Maddalena MVM – POSITIVE DISPLACEMENT ROTARY PISTON WATER METER

KNX Config

2018-03-17 08_51_54-ETS5™ - Zilverlinde 1

2018-03-17 08_52_16-ETS5™ - Zilverlinde 1

2018-03-17 08_52_34-ETS5™ - Zilverlinde 1

MBus DPT Identifier
The M-Bus was developed for configuration and reading of data from meters and consumption counting devices. The M-Bus is a
bus with a single master that powers and reads out multiple slave devices. Each slave is addressable with an individual ID that is
between 1 and 250. Theoretically up to 250 slave devices could be operated in one M-Bus segment, but the practical number is
determined by the ability of the master to power the devices. The topology is not critical and no termination is required. Maximum
bus length is 4km in theory depending on the baudrate, in practical situations not more than 10m should be aspired for good
noise immunity.
The M-Bus gateway can power up to 3 devices and communicate with them. If only one device is present, this can be addressed
independent of its individual ID with the broadcast ID ( 254 ). This simplifies the configuration of such a minimal system.
Some M-Bus devices can be powered through the M-Bus, others draw current from the internal battery at readout of the data. So
some M-Bus devices only allow a certain number of readings over an amount of time to disburden the internal batteries. The
readout cycles must be choosen accordingly.
Readout of the devices data is initiated by the master by sending a REQ_UD2 ( Request User Data ) telegram. The connected
devices check if they are addressed by comparing their ID and return a RSP_UD ( Respond User Data ) telegram. The RSP_UD
telegram contains up to 252 byte of user data. The user data consists of several data packages each of them beginning with
some identification bytes, the DIF ( Data Information Field ) and the VIF ( Value Information Field ). DIF and VIF can have several
byte, of practical relevance are 1 or 2 byte per field. With 4 byte nearly all data packages can be identified. If a value field
represents a reference value there is usually a date field associated with this value. The information that can be expected in the
DIF and VIF are different with every manufacturer and every device class. Generally the desired informations can be achieved
from the manufacturers. The values for the DIF and VIF must be identified and written into the appropriate fields as strings of
hexadecimal characters.
Water meter
Volume information DIF 04 VIF 13 Data to write into the parameter field: 0413
Reference value DIF 04 VIF 80 13 Data to write into the parameter field: 048013

Electrical Meter
Total consumption DIF 04 VIF 03 Data to write into the parameter field: 0403
Actual consumption DIF 02 VIF 2B Data to write into the parameter field: 022B

Hassio Update

Added offset 16,402 to reflect identical meter value

sensor.yaml

water_consumption_m3:
friendly_name: “Total Water Consumption m3”
unit_of_measurement: ‘m3’
value_template: “{{ (states(‘sensor.waterarcus’)|float / 1000 + 16.402) | round(0) }}”

Gasmeter in Hager Domovea

2017-12-09 10_32_24-Configuratie software voor Domovea

1: Cumulatieve waarde
Totaal verbruik op KNX bus in m³

2: Momentane waarde
Actief verbruik op KNX bus in m³ / uur

3: Stapgrootte
Aangezien ik tot 2 cijfers na de komma als 1 decimaal getal op de bus verstuur dien ik de stapgrootte aan te passen van 1 naar 0.01. Bv: 670125 op de KNX bus is 6701,25 m³

De correcte momentane waarde visualiseren was een ander paar mouwen. Het moeilijkste stuk was achterhalen welke waarde de Hager TJA450 gebruikt om het momentaan gasverbruik uit te lezen. Na het uittesten van verschillende bus writes via de domovea configuration tool (automatisering) ben ik erachter gekomen dat er een 4 bytes float waarde nodig is vooraleer de Gauss meter in beweging treedt.

2017-12-09 22_45_02-Configuratie software voor Domovea

Na het testen van de verschillende datapoints had ik eindelijk succes met de 4 bytes Float value.

Hier merkte ik ook op dat na het verzenden van de waarde 1 de Gauss meter in de visualisatie 3600 m³ gas aangaf. Dit nam ik mee voor de latere berekening dat ik hoogstwaarschijnlijk nog eens mijn momentaan verbruik zal moeten delen door 3600 (of vermenigvuldigen met 0.000278)

Een 2de obstakel was mijn float waarde van het momentane verbruik omzetten naar een hexadecimale waarde. Ook dit heb ik uiteindelijk kunnen verwezenlijken door het gebruik van een python scriptje. Vanuit bash roep ik een python functie op en gebruik de return value ervan als hexadecimale waarde.

Het script loopt via crontab elke minuut en zal 5x dezelfde waarde in deze minuut op de bus uitsturen (elke 10 seconden). 1 update van het momentaan gasverbruik per minuut lijkt me voldoende. De reden om de waarde elke 10 seconden op de bus uit te sturen is omdat de domovea visualisatie na 20 seconden > durft terug te vallen op 0.

Gebruikte scripts:

crontab config

crontab -e
*/1 * * * * /root/scripts/knxScripts/gasToBus.sh

Bash script

#!/bin/bash
# Uitlezen gaswaarde via TRC5000 en RPI3
# Via crontab elke minuut momentaan verbruik starten, dit script zal 5x 10 seconden slapen en dezelfde waarde versturen
log="/root/logs/gasToBus.log"

# ophalen huidig gasverbruik
consumption=$(</var/run/shm/gascounter)

# ophalen vorig gasverbruik
pconsumption=$(</root/scripts/knxScripts/gasToBus.lastdata)

# berekenen nieuw verbruik
nconsumption=$(expr $consumption - $pconsumption)

# omzetten naar m^3/h
# script loopt elke 60 seconden
# 0,01 = 1 puls
# nconsumption = aantal nieuwe pulsen in 1 minuut
# nconsumption x 60 = aantal pulsen / uur
# hconsumption = hourly consumption
# 1/3600 = 0,000278 => 4 byte floatwaarde hourly consumption
hconsumption=$(echo $nconsumption*60/100 | bc -l)
hconsumption=$(echo $hconsumption*0.000278 | bc -l)

#afronden niet nodig
#hrconsumption=$(echo "($hconsumption)/6" | bc)

hexbusformat=`python /root/scripts/knxScripts/floatToHex.py "$hconsumption"`

#echo "$hrconsumption -> $whex"
#printf -v hexconsumption "%08x" "$hrconsumption"
#hexbusformat=$(echo $hexconsumption | sed 's/.\{2\}/& /g')

#echo "$(date "+%Y%m%d %T") Wegschrijven momentaan verbruik op KNX bus 4/6/16 -> dec: $hconsumption -> hex: $hexbusformat" >> $log
for i in {1..5}
do
 knxtool groupwrite local:/run/knx 4/6/16 $hexbusformat
 #echo "$(date "+%Y%m%d %T") iteratie $i -> write $hexbusformat done" >> $log
 sleep 10
done

# wegschrijven van nieuwe lastdata
#echo "$(date "+%Y%m%d %T") wegschrijven momentaan verbruik naar lastdata > $consumption" >> $log
echo $consumption > /root/scripts/knxScripts/gasToBus.lastdata
echo "$(date "+%Y%m%d %T") 5x groupwrite 4/6/16 -> $hexbusformat" >> $log

Python script

#!/usr/bin/python
import struct
import os
import sys
def float_to_hex(f):
return hex(struct.unpack('<I', struct.pack('<f', f))[0])
whex = float_to_hex(float(sys.argv[1]))
whex = whex.replace('0x','')
whex=' '.join([whex[i:i+2] for i in range(0, len(whex), 2)])
if whex == "0":
print "00 00 00 00"
sys.exit(0)
else:
print whex
sys.exit(0)

#whex = float_to_hex(0.000556)
#print whex
#plaats hexadecimaal telegram op de bus (via bash commando)
#wcommand = "knxtool groupwrite local:/run/knx 4/6/16 " + whex
#os.system(wcommand)

 

Het resultaat:

2017-12-09 22_56_53-Domovea2017-12-09 22_57_04-Domovea

230v deurbel i.c.m. klassieke belknop

Materiaal

Gebruikte gong: Friedland D3230 – Big Beng – 230v

friedland-d3230

Gebruikte deurbel: Niko

8809443950622_5412748030853_1_45517_tif_picture_170wx170h

KNX input: Hager TX302 (2 kanalen)

tx302

KNX output: Hager TXA201B (1 kanaal 230v)

d4633b42757dbefdec866a65743f3660

Configuratie

De Niko deurbel wordt aangesloten op 1 van de 2 kanalen van de TX302.

Het relais van de KNX output wordt aangesloten op klemmen 1 en 3 van de Friedland gong.

De transfo van de gong wordt voorzien van 230v.

Initieel had ik de deurbel aangestuurd via een ON/OFF schakeling op de KNX input TX302. Wanneer er een bezoeker op de deurbel duwde werd de KNX output TXA201B geschakeld. Op deze manier emuleerde ik de situatie wanneer er een analoge drukknop zou aangesloten zijn op de klemmen 1 en 3 van de gong. Na programmatie en testen bleek dit zoals verwacht te functioneren. De deurbel deed “DING” bij het indrukken van de knop. Wanneer ik de knop loste kwam de “DONG”.

Na een tijdje bleek dat sommige bezoekers op de deurbel duwde en er helemaal niets gebeurde. Na analyse had dit te maken met het feit dat deze bezoekers enorm snel op de bel duwden. (<200ms)

Bij een klassieke situatie worden de klemmen 1 en 3 kortgesloten, hoe kort je ook maar op de deurbel duwt. Hier treedt dus nooit een probleem op. Bij mij is de INPUT en de OUTPUT van elkaar gescheiden en wordt er eerst via KNX telegrammen gecommuniceerd.

Na de analyse werd duidelijk dat de input wel degelijk het telegram op de bus plaatste. Hiermee wist ik dat ik aan de slag zou kunnen om het probleem bij de output op te lossen.

De oplossing was relatief eenvoudig: i.p.v. een ON/OFF input signaal te versturen heb ik de TX302 geherprogrammeerd om een TIMER object uit te sturen. Op mijn KNX output heb ik een timer van 1 seconde ingesteld en zo schakelt hij in alle gevallen langer dan 200ms.

Het resultaat:

Snel op de knop duwen aan de voordeur: telegram op BUS , output schakelt in = DING –> TIMER 1seconde –> output schakelt uit = DONG

Blijven duwen op de knop aan de voordeur: Ook hier volgt nu de DONG na 1 seconde. Dit is dus verschillend met een klassieke situatie zonder KNX. Maar een deurbel dient natuurlijk niet om te blijven op duwen. In feite is het nu zelfs beter want de transfo blijft nu niet onder spanning staan voor zolang er iemand blijft duwen op de knop.

ETS5 Configuratie

deurbel-input1deurbel-input2deurbel-output1deurbel-output2

 

UPDATE:

Blijkt na een tijdje dat ik vastgesteld heb dat de TXB302 2 soorten lang duwen ondersteunt.

txb302langduwen

In de praktijk gebeurt er niets bij een druktoets langer dan 1 seconde i.c.m. het timer object. Dus nu had ik het probleem als iemand langer dan 1 seconde duwde dat er ook geen GONG optrad. Nu zal er waarschijnlijk niemand langer dan 1 sec op deze knop duwen maar het is niet ideaal.

Na wat verder zoeken ben ik op een 2de en betere oplossing gekomen. Ik maak nu terug gebruik van de klassieke ON/OFF op de TXB302. Op de TXB201a heb ik een optie gevonden om een tijdsvertraging voor uitschakelen in te stellen. Hier heb ik 0,5 seconden gekozen. Dus het contact wordt met 0,5 seconden vertraagd vooraleer deze uitschakelt.

txb201a_uitschakelvertragingpng

Hierdoor elimineer ik ook het probleem dat er niet korten dan 0,5 seconden op de bel kan geduwd worden. (waardoor de DING DONG soms niet optrad)

 

Hager Domovea Custom Reporting

De Hager Domovea TJA450 server biedt geen mogelijkheid om data automatisch te exporteren naar een database. Via de servermanager kan je de historische data van meetwaarden wel downloaden naar een csv of xml bestand maar daar houdt het dus ook op.

Persoonlijk vind ik het interessant om bv bij te houden hoeveel keer een bepaald event zich voorgedaan heeft. bv: het openen van de achterdeur of garagepoort.

De domovea server is wel in staat om emails te sturen. Dus de idee ontstond al snel om elke week een rapportje naar mezelf te mailen met een overzichtje van wat er allemaal gebeurd is.

BV: Magneetcontact achterdeur gaat open

–> busevent komt bij de domovea server

domoveastats1

domoveastats2

–> de domovea server doet de variabele achterdeurOpen + 1

domoveastats3

–> zondagnacht verstuurt de domoveaserver een rapportje en reset alle variabelen.

domoveastats4

domoveastats5

 

Zo een wekelijks rapportje ziet er als volgt uit

————————————————————–
START DOMOVEA REPORT
————————————————————–

Weekly Facts:

– Aantal keer garage geopend: 34
– Aantal keer schuifraam geopend: 27
– Aantal keer achterdeur geopend: 164
– Aantal keer voordeur geopend: 7
– Aantal keer alarm ingeschakeld: 6
– Buitenalarm afgegaan: 0
– Binnenkomst als alarm nog actief was (Lichten pinken): 1
– Aantal keer op de deurbel geduwd: 4
– Aantal keer de filmmodus ingeschakeld: 0
– Aantal keer nachtmodus aangezet: 7

————————————————————–
Variabelen Check:

Status Filmmodus: Vals (0)
Status AlarmNetAan: Vals (0)
Status DeurbelVerlichting: Vals (0)

————————————————————–
END DOMOVEA REPORT
————————————————————–

 

Het zou interessant zijn mocht er een mogelijkheid bestaan om zelf een logfile aan te maken of de waarden vanuit domovea rechtstreeks te kunnen wegschrijven in een database. Maar tot op heden is dit dus niet het geval.

Als workaround heb ik een python scriptje geschreven die deze mailtjes uitleest uit mijn gmail account en wegschrijft in een MySQL tabel.

import os
import sys
import datetime
from gmail import Gmail

## Important notes
# give stijn_domovea file permissions for writing files to NAS!
#
# UPDATE mysql.user SET File_priv = 'Y' WHERE user='stijn_domovea' AND host='localhost';
# 1 rij bijgewerkt.
# FLUSH PRIVILEGES;
# MySQL gaf een lege resultatenset terug (0 rijen).

# Vars
mysqlbin="/usr/bin/mysql"
mysqlhost="localhost"
mysqlport="3306"
#mysqluser="xxx"
mysqluser="xxx"
mysqldb="xxx"
#mysqlpass="xxx"
mysqlpass="xxx"

MySQLOutFile = "/tmp/tmpWRdata.txt"
LogOutFile = "/volume2/data/scripts/DomoveaStats/log/processedDomoveaStats.log"

# Classes
class Report:
def __init__(self, date, garage, schuifraam, achterdeur, voordeur, alarm_aan, alarm_actief, alarm_stil, deurbel, filmmodus, nachtmodus):
self.date = date
self.garage = garage
self.schuifraam = schuifraam
self.achterdeur = achterdeur
self.voordeur = voordeur
self.alarm_aan = alarm_aan
self.alarm_actief = alarm_actief
self.alarm_stil = alarm_stil
self.deurbel = deurbel
self.filmmodus = filmmodus
self.nachtmodus = nachtmodus

def toString(self):
datest = str(self.date)
st = "reportdate %s - garage %d - schuifraam %d - achterdeur %d - voordeur %d - alarm_aan %d - alarm_actief %d - alarm_stil %d - deurbel %d - filmmodus %d - nachtmodus %d" % (datest, self.garage, self.schuifraam, self.achterdeur, self.voordeur, self.alarm_aan, self.alarm_actief, self.alarm_stil, self.deurbel, self.filmmodus, self.nachtmodus)
return st

def sql(sqlcmd):
os.system(mysqlbin + " -h" + mysqlhost + " -P" + mysqlport + " -u" + mysqluser + " -p" + mysqlpass + " -e " + sqlcmd)

# Body
# Retrieve mails
g = Gmail()
g.login("xxx@gmail.com", "onetimeapplicationpassword")
mails = g.label("DeLinde/WeeklyStats").mail(prefetch=True)

# Build array with reports
allReports = []
x = 0
totalmails = len(mails)

# Quit when gmail label is empty !
if totalmails == 0:
print "no reports found --> exiting script!"
exit(0)

while x < totalmails:
r = Report(0,0,0,0,0,0,0,0,0,0,0)
r.date = mails[x].sent_at
bl = mails[x].body.split('\n')

r.garage = int(filter(str.isdigit, bl[7]))
r.schuifraam = int(filter(str.isdigit, bl[8]))
r.achterdeur = int(filter(str.isdigit, bl[9]))
r.voordeur = int(filter(str.isdigit, bl[10]))
r.alarm_aan = int(filter(str.isdigit, bl[11]))
r.alarm_actief = int(filter(str.isdigit, bl[12]))
r.alarm_stil = int(filter(str.isdigit, bl[13]))
r.deurbel = int(filter(str.isdigit, bl[14]))
r.filmmodus = int(filter(str.isdigit, bl[15]))
r.nachtmodus = int(filter(str.isdigit, bl[16]))
allReports.append(r)

x = x + 1
print "Done! building report objects"

# Build MySQL connection & update stijn_domovea database
try:
file = open(LogOutFile, "ab")
# get all added dates, on this base we will filter reports already added to DB. In this way we will never add duplicate files
# sql("'use stijn_domovea; select date from WeeklyReports INTO OUTFILE \"/volume2/data/scripts/DomoveaStats/tmpWRdata.txt\";'")
sql("'use stijn_domovea; select date from WeeklyReports INTO OUTFILE \"/tmp/tmpWRdata.txt\";'")

for ar in allReports:
#check date already in DB
date = str(ar.date)
if date in open(MySQLOutFile).read():
print "found %s already in db." % date
else:
sqlstr = "'use stijn_domovea; INSERT INTO WeeklyReports (date,garage,schuifraam,achterdeur,voordeur,alarm_aan,alarm_actief,alarm_stil,deurbel,filmmodus,nachtmodus) VALUES (\"%s\",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d);'" % (str(ar.date), ar.garage, ar.schuifraam, ar.achterdeur, ar.voordeur, ar.alarm_aan, ar.alarm_actief, ar.alarm_stil, ar.deurbel, ar.filmmodus, ar.nachtmodus)
sql(sqlstr)
#print "%s --> Totaal aantal keer garagepoort geopend: %d" % (str(ar.date), ar.garage)
#print sqlstr
print "added %s to db." % date
# append entry to log
logline = "date added: " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " --> " + ar.toString() + "\n"
#with open(LogOutFile, "a") as myfile:
# myfile.write(logline)
file.write(logline)
file.write(u"\r\n")

# Remove temporary file
os.remove(MySQLOutFile)

file.close()

except mdb.Error, e:
# truncate temporary file
os.remove(MySQLOutFile)
# open(MySQLOutFile, 'w').close()

print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)

finally:

sys.exit(0)

 

Uitlezen Hager TE360 met KNXD

Inleiding

Dit script zal de totale verbruikte energie (in Watt) van een Hager TE360 ophalen en toevoegen aan een MySQL database.

Het groepsadres dat gebruikt wordt is 4/6/9
TE360 – 9 – TE360 – totale actieve energie tarief 1 + 2 (Wh)

Dependencies

MySQL client om data weg te schrijven naar de MySQL database

apt-get install mysql-client

Basic Calculator (BC)

apt-get install bc

 

Actieve KNXD logfile (niet meer van toepassing)

crontab -e
@reboot knxtool log local:/run/knx

knxd tools

knxtool groupreadresponse

 

Script die Hager TE360 bevraagt en resultaat in textbestand wegschrijft:

log=/root/logs/getTotalConsumption.log
knxresult=/root/scripts/getTotalConsumption.knxresult
data=/root/scripts/getTotalConsumption.data

echo "$(date "+%Y%m%d %T") ## start ophalen totaal verbruik van Hager TE360 ##" >> $log

echo "$(date "+%Y%m%d %T") uitlezen TE360 met knxtool groupreadresponse" >> $log
#knxtool groupreadresponse local:/run/knx 4/6/9 > $knxresult
knxtool groupreadresponse ip:localhost 4/6/9 > $knxresult

hexdata=$(cat $knxresult | grep -m 1 "from 1.1.9:" | cut -d ":" -f 2)
echo "$(date "+%Y%m%d %T") hexadecimale energiewaarde extraheren: $hexdata" >> $log

# controle opgehaalde hexadecimale waarde
if [ -z "$hexdata" ]; then
echo "$(date "+%Y%m%d %T") fout met uitlezen hexadecimale waarde" >> $log
echo "$(date "+%Y%m%d %T") hexadecimale waarde is leeg" >> $log
echo "$(date "+%Y%m%d %T") script wordt gestopt!" >> $log
exit
fi
if ! [[ $hexdata =~ [!0-9A-Fa-f] ]]; then
echo "$(date "+%Y%m%d %T") fout met uitlezen hexadecimale waarde" >> $log
echo "$(date "+%Y%m%d %T") hexadecimale niet correct: $hexdata" >> $log
echo "$(date "+%Y%m%d %T") script wordt gestopt!" >> $log
exit
fi

# verwijderen spaties
hexdata="$(echo -e "${hexdata}" | tr -d '[[:space:]]')"

# omzetten naar decimale waarde
echo "$(date "+%Y%m%d %T") omzetten hexadecimale waarde naar decimale waarde en wegschrijven naar $data" >> $log
echo $((16#$hexdata)) > $data

echo "$(date "+%Y%m%d %T") ## einde ophalen totaal verbruik van Hager TE360 ##" >> $log

 

Script die elke 5 minuten de database met meetwaarden update:

#!/bin/bash

# Uitlezen energiewaarde Hager TE360 via knxd
# Nadien het totaal verbruik van de afgelopen 5 minuten berekenen
# en wegschrijven naar de SQL database.

log="/root/logs/electricityToMySQL.log"
mysql_host=xx
mysql_user=xx
mysql_pass=xx
mysql_db=xx

# db connectie testen
# indien niet mogelijk script direct stoppen zodat later de correcte waarde in de db kan worden toegevoegd.
if ! mysql -h $mysql_host -u $mysql_user -p$mysql_pass -e "use $mysql_db"; then
echo "$(date "+%Y%m%d %T") db connection error -> script wordt gestopt" >> $log
exit
fi

echo "$(date "+%Y%m%d %T") ## start ophalen elektriciteit ##" >> $log

# ophalen huidig verbruik
echo "$(date "+%Y%m%d %T") uitlezen TE360 met knxtool groupreadresponse" >> $log
/root/scripts/getTotalConsumption.sh
currdata=$(</root/scripts/getTotalConsumption.data)

# ophalen totaalverbruik MySQL database
consumptionTotal=$(mysql -h $mysql_host $mysql_db -u $mysql_user -p$mysql_pass -e "SELECT consumptionTotal FROM Electricity ORDER BY id DESC LIMIT 1;")
consumptionTotal=$(echo $consumptionTotal | cut -d " " -f2)
echo "$(date "+%Y%m%d %T") Vorig totaal verbuik: $consumptionTotal watt" >> $log

# ophalen waarde van 5 minuten geleden
lastdata=$(</root/scripts/electricityToMySQL.lastdata)

# berekenen verbruik laatste 5 minuten
consumption=$(expr $currdata - $lastdata)
echo "$(date "+%Y%m%d %T") Energieverbruik laatste 5 minuten: $consumption watt" >> $log

consumptionTotal=$(($consumptionTotal + $consumption))

# ophalen prijs piek- en daluren
q=$(mysql -h $mysql_host $mysql_db -u $mysql_user -p$mysql_pass -e "SELECT priceHigh,priceLow FROM ElectricityPrice ORDER BY id DESC LIMIT 1;")
priceHigh=$(echo $q | cut -d " " -f3)
priceLow=$(echo $q | cut -d " " -f4)
echo "$(date "+%Y%m%d %T") kostprijs piek: $priceHigh, kostprijs dal: $priceLow" >> $log

# berekenen kostprijs verbruikte energie
# huidige uur
h=$(date +%H)
#dag van de week 1=maandag, 7=zondag
dow=$(date +%u)
# huidig tarief
ct="dal"
if [[ $dow -gt 5 ]] ; then
#echo "$h -> dal -> weekend"
conPrice=$(echo $consumption*$priceLow/1000 | bc -l)
elif (( 7 <= 10#$h && 10#$h < 22 )) ; then
#echo "$h -> piek"
conPrice=$(echo $consumption*$priceHigh/1000 | bc -l)
ct="piek"
else
#echo "$h -> dal"
conPrice=$(echo $consumption*$priceLow/1000 | bc -l)
fi

# toevoegen waarde is MySQL database
date=$(date +"%Y-%m-%d")
time=$(date +"%T")
echo "$(date "+%Y%m%d %T") toevoegen data aan MySQL -> tarief: $ct - verbruik: $consumption - kostprijs: $conPrice --> stijn_domovea -> Electricity" >> $log

mysql -h $mysql_host $mysql_db -u $mysql_user -p$mysql_pass -e "insert into Electricity (date,time,consumption,consumptionTotal,price) values ('$date','$time','$consumption','$consumptionTotal','$conPrice')"

# wegschrijven van nieuwe lastdata
echo "$(date "+%Y%m%d %T") wegschrijven totaal verbruik naar tekstfile -> totaalverbruik: $currdata" >> $log
echo $currdata > /root/scripts/electricityToMySQL.lastdata

echo "$(date "+%Y%m%d %T") ## einde ophalen elektriciteit ##" >> $log

Toevoegen aan crontab

*/5 * * * * /root/scripts/electricityToMySQL.sh

 

Checks, Monitoring & Backup

Hieronder een overzicht van alle controles die geïmplementeerd zijn.

Het komt er op neer dat er thuis 2 toestellen continue draaien

  • RPI3
  • Synology

Beide toestellen controleren elkaar en sturen indien nodig email alerts uit.

De RPI3 heeft ook een M/Monit webinterface waar alles visueel en met historiek kan nagekeken worden.

mmonit

Het is belangrijk dat er een werkende internetverbinding aanwezig is zodat er ten alle tijde emails kunnen verstuurd worden. Ik gebruik hiervoor de mailserver van telenet (uit.telenet.be) en heb op beide toestellen een secondary dns server geconfigureerd zodat de mailserver altijd resolveable zal zijn.

Beide toestellen inclusief internetverbinding (modem / router)  hangen aan een backup-UPS 650. Zo zal bij kort stroomverlies geen uitval zijn. (< 1u)

Monitoring & Checks

RPI3

  • Monit Agent
  • M/Monit visualisatie

Email alerting via uit.telenet.be

Synology

Controle meetwaarden elektriciteit
Python script dat elke 5 minuten controleert indien er nieuwe meetwaarden in de database binnenkomen.

Kort samengevat kunnen we met dit script het volgende vaststellen

  1. De RPI3 staat aan
  2. KNXD service draait
  3. De RPI3 kan de Hager TE360 uitlezen –> de Energiemeter functioneert goed
  4. De DB van de synology draait en is up to date
import os
import sys
import datetime

# Import smtplib for the actual sending function
import smtplib

# Import the email modules we'll need
from email.mime.text import MIMEText

# Vars
mysqlbin="/usr/bin/mysql"
mysqlhost="localhost"
mysqlport="3306"
mysqluser="xxx"
mysqldb="xxx"
mysqlpass="xxx"

# File Vars
MySQLOutFile = "/tmp/tmpWRdata.txt"
LogOutFile = "/volume2/data/scripts/log/checkElectricity.log"
DateLastMailFile = "/volume2/data/scripts/log/checkElectricity.lastmail"

# Email Vars
smtphost = "uit.telenet.be"
me = "synology@domovea.com"
you = "skitex@gmail.com"

def sql(sqlcmd):
os.system(mysqlbin + " -h" + mysqlhost + " -P" + mysqlport + " -u" + mysqluser + " -p" + mysqlpass + " -e " + sqlcmd)

# Body
# Build MySQL connection & update database
try:
file = open(LogOutFile, "ab")
# get all added dates, on this base we will filter reports already added to DB. In this way we will never add duplicate files
# sql("'use stijn_domovea; select date from DailyStats INTO OUTFILE \"/volume2/data/scripts/DomoveaStats/tmpWRdata.txt\";'")
sql("'use stijn_domovea; SELECT * FROM Electricity ORDER BY id DESC LIMIT 1 INTO OUTFILE \"/tmp/tmpWRdata.txt\";'")

file2 = open(MySQLOutFile, "r")
lastDBEntry = file2.read()
file2.close()

# Remove temporary file
os.remove(MySQLOutFile)

#Array maken van SQL record
#0: ID
#1: DATE
#2: TIME
#3: CONSUMPTION
#4: CONSUMPTIONTOTAL
lastDBEntry = lastDBEntry.split('\t')

#ophalen tijd waarop laatste email verstuurd is
file3 = open(DateLastMailFile, "r")
timelastsend = file3.read()
file3.close()
form = '%Y-%m-%d %H:%M:%S.%f'
timels = datetime.datetime.strptime(timelastsend,form)
timedelta3hours = datetime.timedelta(hours=3)
timenow = datetime.datetime.today()

#Controle op CONSUMPTION = 0
#Dit wordt weggeschreven indien de KNXD tool geen correcte waarde kan uitlezen van de BYS
if lastDBEntry[3] == '0':
print "Fout: vermogen is 0"
#print unicode(timels)
#print unicode(timenow)
#print unicode(timedelta3hours)
if timels >= timenow - timedelta3hours:
print "tijd is niet ouder dan 3 uur"
print "stuur geen email"
else:
print "tijd is ouder dan 3 uur"
print "stuur email en update tijd"

#stuur email
body = "laatste entry: \nid: %s \ndatum: %s \ntijd: %s \nverbruik: %s watt \ntotaal: %s watt" % (lastDBEntry[0],lastDBEntry[1],lastDBEntry[2],lastDBEntry[3],lastDBEntry[4].rstrip('\n'))
# Create a text/plain message
msg = MIMEText(body)
msg['Subject'] = 'Elektriciteit: Foutieve waarde in DB'
msg['From'] = me
msg['To'] = you

# Send the message via our own SMTP server.
s = smtplib.SMTP(smtphost)
s.sendmail(me, [you], msg.as_string())
s.quit()

#update tijd
file3 = open(DateLastMailFile, "w+")
file3.write(unicode(timenow))
file3.close()

#Sluit logfile en stop script
file.close()
sys.exit(0)

#Controle op Datum en Tijd niet ouder dan 5 minuten!
sqldate = "%s %s" % (lastDBEntry[1],lastDBEntry[2])
form = '%Y-%m-%d %H:%M:%S'
timeindb = datetime.datetime.strptime(sqldate, form)
timedelta = datetime.timedelta(seconds=305)

#de tijd in de database moet altijd groter zijn als de huidige tijd - 5 min
if timeindb >= timenow - timedelta:
print "tijd is niet ouder als 5 min"
print timeindb
print timenow
logline = "OK: " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " --> " + sqldate + " --> " + lastDBEntry[3]
file.write(logline)
file.write(u"\r\n")
else:
logline = "Probleem met laatste elektriciteitswaarde in DB: " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " --> " + sqldate + " --> " + lastDBEntry[3]
file.write(logline)
file.write(u"\r\n")
print "stuur email met oude data indien er de laatste 3 uur geen email gestuurd is."

if timels >= timenow - timedelta3hours:
print "tijd is niet ouder dan 3 uur"
print "stuur geen email"
else:
print "tijd is ouder dan 3 uur"
print "stuur email en update tijd"

#stuur email
body = "laatste entry: \nid: %s \ndatum: %s \ntijd: %s \nverbruik: %s watt \ntotaal: %s watt" % (lastDBEntry[0],lastDBEntry[1],lastDBEntry[2],lastDBEntry[3],lastDBEntry[4].rstrip('\n'))
# Create a text/plain message
msg = MIMEText(body)
msg['Subject'] = 'Elektriciteit: Er komen geen meetwaarden meer binnen in de DB'
msg['From'] = me
msg['To'] = you

# Send the message via our own SMTP server.
s = smtplib.SMTP(smtphost)
s.sendmail(me, [you], msg.as_string())
s.quit()

#update tijd
file3 = open(DateLastMailFile, "w+")
file3.write(unicode(timenow))
file3.close()

file.close()

except mdb.Error, e:
# truncate temporary file
os.remove(MySQLOutFile)
# open(MySQLOutFile, 'w').close()

print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)

finally:
sys.exit(0)

Email alerting elke 3 uur via uit.telenet.be

Backup

Synology

SQL Database
Backup location /volume2/data/Domotica/Database
Backup script /volume2/data/scripts/Backup/domotica.sh

#!/bin/ash
find /volume2/data/Domotica/Database -type f -mtime +365 -exec rm {} \;
DBNAME=xxx
DATE=`date +"%Y%m%d"`
SQLFILE=$DBNAME-${DATE}.sql
mysqldump --opt --user=stijn_domovea --password=xxx $DBNAME > $SQLFILE
gzip $SQLFILE
SQLFILE=$SQLFILE.gz
mv $SQLFILE "/volume2/data/Domotica/Database/"$SQLFILE

Script houdt de laatste de backups bij van de laatste 7 dagen. De PC-living houdt via syncbackfree alle historische backups bij.

PC-living
Kritische NAS data naar interne schijf
Via SyncBackFree

  • \\fietology.zilverlinde.home\data\Domotica
  • \\fietology.zilverlinde.home\data\Film
  • \\fietology.zilverlinde.home\data\Fotos
  • \\fietology.zilverlinde.home\mobofietje
  • \\fietology.zilverlinde.home\stufjes\Music
  • \\fietology.zilverlinde.home\data scripts
  • \\fietology.zilverlinde.home\web

Schema: Elke zondag tussen 9u ’s morgens en 18u ’s avonds. Indien gemist zo snel mogelijk uitvoeren na opstart PC.

RPI3

Weekly backup naar fietology (via NFS mounts)

NASLOCATION=/mnt/nasdata/Domotica/SennePi/backup
find $NASLOCATION -type f -mtime +365 -exec rm {} \;
DATE=`date +"%Y%m%d"`
FILE="/tmp/BACKUPSennePi-${DATE}.tar.gz"
tar -hzcvf $FILE /root
mv $FILE $NASLOCATION

Edit: added tar -h option to follow symlinks. In /root heb ik enkele symlinks aangemaakt met config files die ik graag meeneem in de backup. door de parameter -h mee te geven zal mijn tar archief niet de snelkoppeling maar het volledige bestand opnemen in de backup.

 root@SennePi:~ # ln -s /etc/monit/monitrc monitrc
root@SennePi:~ # ln -s /var/spool/cron/crontabs/root crontab
root@SennePi:~ # ln -s /etc/knxd.conf knxd

Google Drive
Meerdere lokale syncs

Monit

Er is dringend nood aan monitoring van alle interne apparaten. Het is dan ook zeer belangrijk dat ik onmiddellijk een email kan krijgen wanneer de RPI niet beschikbaar meer zou zijn. Het belangrijkste is dat de RPI een zo klein mogelijke downtime kent omdat deze instaat voor periodieke metingen. Hoe minder downtime hoe meer meetwaarden dus.

Mijn ogen vielen op de opensource tool Monit. Deze tool is compatibel met ARM processoren zoals de RPI en kan via apt-get eenvoudig geïnstalleerd worden.

https://mmonit.com/monit/

Installatie agent

apt-get install monit

Controle onboot

Controleer dat START=yes voorkomt in

vim /etc/default/monit

 

Installatie Monitoring Server (M/Monit)


cd /opt
wget https://mmonit.com/dist/mmonit-3.5.1-linux-arm.tar.gz
tar -xvf mmonit-3.5.1-linux-arm.tar.gz

Autostart M/Monit via Monit Agent

vim /etc/monit/monitrc
check process mmonit with pidfile /opt/mmonit-3.5.1/logs/mmonit.pid
start program = "/opt/mmonit-3.5.1/bin/mmonit"
stop program = "/opt/mmonit-3.5.1/bin/mmonit stop"

Autostart M/Monit via systemctl

cd /lib/systemd/system
vim mmonit.service

[Unit]
Description = Easy, proactive monitoring of Unix systems, network and cloud services
After = network.target

[Service]
Type=forking
ExecStart = /opt/mmonit-3.5.1/bin/mmonit start
ExecStop = /opt/mmonit-3.5.1/bin/mmonit stop
PIDFile = /opt/mmonit-3.5.1/logs/mmonit.pid

[Install]
WantedBy = multi-user.target

systemctl enable mmonit
systemctl start mmonit
systemctl status mmonit

 

Monit Agent koppelen

vim /etc/monit/monitrc

 

set mmonit http://monit:password@192.168.10.15:8080/collector

set httpd port 2812
allow localhost
allow 192.168.10.15
allow monit:password

 

Extra service toevoegen

check device root with path /dev/root
 if SPACE usage > 80% then alert

check process sshd with pidfile /var/run/sshd.pid
start program "/etc/init.d/ssh start"
stop program "/etc/init.d/ssh stop"
if failed port 22 protocol ssh then restart

check process knxd
matching "knxd";
start program = "/etc/init.d/knxd start"
stop program = "/etc/init.d/knxd stop"
# not working: if failed unixsocket /run/knx then alert

check host fietology.zilverlinde.local with address 192.168.10.5
if failed ping then alert
if failed port 3306 protocol mysql with timeout 15 seconds then alert
if failed port 80 protocol http
and request /domotics/assets/monitcheck with content = "MMonit OK"
then alert

check host cam-voordeur.zilverlinde.local with address 192.168.10.81
if failed ping then alert

check host cam-garage.zilverlinde.local with address 192.168.10.80
if failed ping then alert

check host onkyo.zilverlinde.local with address 192.168.10.41
if failed ping then alert

root@raspberrypi:/etc/monit # monit reload
Reinitializing monit daemon

 

Hager TU402 afstandsbediening

Een TU402 is een draadloze RF afstandsbediening met 2 druktoetsen van Hager welke communiceert via de TR131A en zo KNX telegrammen op de bus kan versturen.

Hager_TU402

 

Voeg het knx product TU402 toe aan de TP lijn voor RF producten.

TU402_1

TU402_2

Configureer de parameters

TU402_3

TU402_4

1 = drukknop licht
2 = rolluik op / neer

Hier zit dus een bug in de applicatie:
De 3de selectie geeft mij het gewenste resultaat met de rolluiken.

Configureer de groepsobjecten

TU402_5

Open de TR313A plugin

RESET device out of installation

Met deze functie kan je een reeds gekoppeld RF toestel terugbrengen naar de fabrieksinstellingen.

TU402_6

TU402_7

Kies voor:
Unidirectional Device with addr. button

Na het resetten klik je het product aan in de lijst en kies je voor Addressing links boven. Met deze knop kan het RF product opnemen in het project.

TU402_8

Indrukken van Cfg. Knop (blauw knopje op de achterkant van de TU402)

TU402_9

Na het adresseren komt er een draadloos icoontje voor knx device address te staan. Hieraan kan je zien dat het nieuwe product toegevoegd is in het project.

TU402_10

Nu rest ons nog enkel de ETS groepsadressen die we eerder reeds toegekend hadden te koppelen in de TU402. Dit doe je door de gegevens te downloaden. (linksboven op selected duwen voor het starten van de download)

TU402_11

Als alles goed verlopen is krijg je normaal gezien onderstaand resultaat.

TU402_12