Homematic und Google Kalender

Die Homematic CCU2 wird bei uns zur Heimautomatisierung eingesetzt.
Hier stelle ich vor, wie ich aus einem Google Kalendar Termine in der CCU zugreifbar mache.

Überblick
Es wird ein Goolge-Script angelegt, welches Termine aus dem Kalender ausliest und auf Vorkommen von Worten überprüft. Das Ergbenis wird aufbereitet als Booleans bereitgestellt. Die CCU ruft dieses Google-Script als Programm auf und schreibt die empfagenen Booleans in SystemVariablen.

Google-Script
Das Anlegen eines Google-Scriptes geht (vielleicht mit einem frischen GoogleAccount für die CCU) einfach, indem man hier ein „Skript als WebApp“ anlegt. Der Editor ist nahezu selbsterklärend – nur ein Hinweis: Version anlegen vor dem Veröffentlichen!

Mein Google-Script sieht so aus:

// Transfer Calendar entries for homematic
//
// This script parses a calendar for given keywords on vacation and away-state
// States are provided as ,-seperated List for easy parsing at the CCU side
// Output, currently:
// VacationToday, AwayToday, AwayNow, VacationTomorrow, AwayTomorrow;
// Feel free to adopt to your needs!
//
// inspired by http://homematic-forum.de/forum/viewtopic.php?t=11386
// by Henning Mersch mailhenning-mersch.de

//Configuration
//Calendar to access
var cal = 'xxxxxxxxxxxxxxxxxxxxxxxxxx@group.calendar.google.com';
//Patterns to search for
var pattVacation=new RegExp('urlaub|vacation|frei','i');
var pattAway=new RegExp('abwesend|verreist|unterwegs','i');

function doGet(request) {
var answer = "2.0";

if ( request.parameters.cmd == "urlaub" )
{
answer = getVacation();
}

return ContentService.createTextOutput(answer);
}

function getVacation()
//creates a bit mask including todays and tomorrows vacation information
{
//init dates
var today = new Date();
today.getTime();
var tomorrow = new Date();
tomorrow.setTime(tomorrow.getTime(­ ) + (1000*3600*24));
//init bit mask and flags
var result = new Array(0,0,0,0,0); //00000 - initial value
var posVacationToday = 0;
var posAwayToday = 1;
var posAwayNow = 2;
var posVacationTomorrow = 3;
var posAwayTomorrow = 4;

//get information about today
var eventsToday = daysEvents(today);
for (var i=0; i<eventsToday.length; i++)
{
//check event title for vacation
if (pattVacation.test(eventsToday[i].getTitle()))
{
result[posVacationToday] = 1;
}
//check event title/location/description for away state
if (pattAway.test(eventsToday[i].getTitle()) || pattAway.test(eventsToday[i].getLocation())|| pattAway.test(eventsToday[i].getDescription()))
{
result[posAwayToday] = 1;
}
}
//get information about current+1h
var oneHoursFromNow = new Date(today.getTime() + (1 * 60 * 60 * 1000));
var eventsNow = CalendarApp.getCalendarById(cal).getEvents(today, oneHoursFromNow);
for (var i=0; i<eventsNow.length; i++)
{
//check title/location/description for away
if (pattAway.test(eventsNow[i].getTitle()) || pattAway.test(eventsNow[i].getLocation())|| pattAway.test(eventsNow[i].getDescription()))
{
result[posAwayNow] = 1;
}
}
//get information about tomorrow
var eventsTomorrow = daysEvents(tomorrow);
for (var i=0; i<eventsTomorrow.length; i++)
{
if (pattVacation.test(eventsTomorrow[i].getTitle()))
{
result[posVacationTomorrow] = 1;
}
//check event title/location/description for away state
if (pattAway.test(eventsTomorrow[i].getTitle()) || pattAway.test(eventsTomorrow[i].getLocation())|| pattAway.test(eventsTomorrow[i].getDescription()))
{
result[posAwayTomorrow] = 1;
}
}
return(result);
}

// corrects a google bug in all day events
// thanks to user "dwm" from homematic-forum.de!
function daysEvents( aDate )
{
var now = new Date( aDate );
now.setHours(12);
now.setMinutes(0);
now.setSeconds(0);

var startOfDay = new Date(now);
startOfDay.setUTCHours(0);
startOfDay.setMinutes(0);
startOfDay.setSeconds(0);
startOfDay.setMilliseconds(0);
var endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000);

var events = CalendarApp.getCalendarById(cal).getEvents(startOfDay, endOfDay);
var result = new Array;

for (var i=0; i<events.length; i++)
{
var theTitle=events[i].getTitle();
if ( events[i].isAllDayEvent() )
{
result.push(events[i]);
}
}

events = CalendarApp.getCalendarById(cal).getEventsForDay( now );
for (var i=0; i<events.length; i++)
{
var theTitle=events[i].getTitle();
if ( !events[i].isAllDayEvent() )
{
result.push(events[i]);
}
}

return result;
}

CCU
Auf der CCU werden entsprechende SystemVariablen angelegt und folgendes Programm ruft per CuxD-System-Exec Gerät (ein solches kann einfach über die CuxD-Oberfläche angelegt werden) per Curl das Google-Script auf.

Hinweis: In Foren liest man häufiger von manuellen Curl Installationen – das ist nicht mehr nötig; mittlerweile liefert CuxD curl selber mit.


! Get Vacation/away from Google Calendar
! inspired by http://homematic-forum.de/forum/viewtopic.php?t=11386
! by Henning Mersch mailhenning-mersch.de
! SystemVariables (bool):
! All-Google-Urlaub
! All-Google-AbwesendHeute
! All-Google-Abwesend
! All-Google-UrlaubMorgen
! All-Google-AbwesendMorgen

var url="https://script.google.com/macros/s/HIER-DIE-SCRIPT-ID/exec";
var cmd = "LD_LIBRARY_PATH=/usr/local/addons/cuxd /usr/local/addons/cuxd/curl -s -k -L " # url # "?cmd=urlaub";

dom.GetObject("CUxD.CUX2801002:1.CMD_SETS").State(cmd);
dom.GetObject("CUxD.CUX2801002:1.CMD_QUERY_RET").State(1);
var v = dom.GetObject("CUxD.CUX2801002:1.CMD_RETS").State();

var oUrlaub = dom.GetObject("All-Google-Urlaub");

!Parse the output
if ( v.StrValueByIndex(",",0) == "1" )
{
dom.GetObject("All-Google-Urlaub").State ( true );
}
else
{
dom.GetObject("All-Google-Urlaub").State ( false );
}

if ( v.StrValueByIndex(",",1) == "1" )
{
dom.GetObject("All-Google-AbwesendHeute").State ( true );
}
else
{
dom.GetObject("All-Google-AbwesendHeute").State ( false );
}

if ( v.StrValueByIndex(",",2) == "1" )
{
dom.GetObject("All-Google-Abwesend").State ( true );
}
else
{
dom.GetObject("All-Google-Abwesend").State ( false );
}

if ( v.StrValueByIndex(",",3) == "1" )
{
dom.GetObject("All-Google-UrlaubMorgen").State ( true );
}
else
{
dom.GetObject("All-Google-UrlaubMorgen").State ( false );
}

if ( v.StrValueByIndex(",",4) == "1" )
{
dom.GetObject("All-Google-AbwesendMorgen").State ( true );
}
else
{
dom.GetObject("All-Google-AbwesendMorgen").State ( false );
}

Das wars schon 🙂

ByeBye vServer

We just moved our webstuff (webpages, emails) from a vServer to a webhosting offer by Alfahosting.

For the last couple of moth I haven’t used any of the advantages of a vServer – and administration of the vServer does take some hours per month. Last few month and most probably next years I won’t have time doing this – so … we searched for a smaller (and as a sideeffekt cheaper) solution for our webpages and email stuff.

Thanks goes to vollmar.net for providing the vServer last 5 years or so – in a very reliable and friedly way. I definetly recommend one of their vServers, if you need one!

Logging (by sending mail) IP (WAN) adress using DD-WRT

An article of the c’t (german only) recommended to log IP adresses, which are assigned to you and might be used for dissuation – even if this is wrong. The article suggested to log IP adresses to have some kind of indication if the dissuation mentions an IP adress which was assigned to you at this time.

Sadly, DD-WRT doesnt has a menu for configuring to store the WAN IP adresses – thus I had to do it manually.

First one needs ssh or telnet access to the box – this could be enabled by the webinterface (services tab). While enabling, also enable "JFFS2 Support"  – a filesystem for permanent storage (Administration->Management tab) – my WRT-54GS is low on this, but this is fine.

Next I adopted this script to my needs – here is my version.(the original one does not react on changes but checks every few seconds if a change is detected)

You need to adopt the first lines of the script to your eMail adress, the mail server to send the mail to. You might adjust subject and content easily.

I stored it in "/jffs/etc/config/wanipcheck.ipup" (dont forget to chmod +x!) , thus it will be executed when the WAN interface comes up. Additionally, one needs the sendmail binary, which is included in the original script download.

It works really nice – even if I would prefer to have something, which could be configured by the normal webinterface of DD-WRT.

Server Migration Howto

We just moved to another vServer with our domains.
This required a fresh installation of the debian system, since the virtualization environment has changed at our Hoster: From CTX to Xen.

I was very confused that I can’t really find some HOWTOs or guides for simple migration of the "normal" server side software like apache2, exim, spamassassin and so on.

Well – I wrote down my process of migration – hopefully its useful for someone 🙂

IANA „acplt 7509/tcp“

Some of you might know, that we (so the chair of process control technology @ RWTH Aachen University) currently redevelop some major parts of our ACPLT Technologies. Main conceptual goals: Get rid of the portmapper and ks_manager components.

Since we are ready to go to production … well…at least our concepts are stable and prototype implementation does work…. I applied for a tcp port at IANA.

Today they assigned
acplt 7509/tcp ACPLT – process automation service
# Henning Mersch 07 December 2010

Thanks IANA.

Old Skool…

From IRC – #k-9 @ freenode (10/8/22, anomymized), I am <HM>

<F>HM:
if you have a custom ROM with proper iptables support, you could use
DroidWall to prevent K-9 from using non-WiFi connections
[…]
<HM>F, *g* I lika that …. cracking a nut with a sledgehammer
<F>;)
[…]
<HM>.oO(I worked with iptables maybe 10 years ago…and I never thought I could use this knowledge on my mobile somdays)
<T>I’ve seen ".oO(…)" 10 years ago and I never thought I’d see it again. 😉
<HM>ROTFL
<T>wow, and a T in "rofl".
<T>You ARE old skool.

Well, Thanks, I know I’m getting old 😉

Ubuntu Lucid Update

Couple of days ago, I updated my machines to Ubuntu Lucid 10.04. Everything works really smoothly: Hardware is recognized and supported, no issues with my xrandr-dual-screen as well as my homesticksyncing. 

Well, KDE got one BIG, LARGE issue. Just google for Akonadi self-test failure.

The Akonadi server is a information server under the hood of KDE – mostly used by the sematic desktop stuff. Prior update I switched the Akonadi server to use a local mysql server for saving some resources. As suggested here, this is done my checking the Akonadi option "Use internal MySQL server". Well, the new version seems to NOT support this option – the server cant start and due to this some KDE applications like kmail and kontact (which I used) cant start up. Even worse: Since the server cant start, there is no GUI to uncheck the "Use internal MySQL server" option!

Afer some investigation and reading this, I figured out a semi-perfect solution: One can simply delete ~/.config/akonadi/akonadiserverrc, which seem to store the "bad" configuration. After deletion, the server could be started but all kontact data seems to be lost. Luckily, this could be imported from "~/.kde/share/apps/kabc", which seems to be the old place for addresses.

This story really gives me to think about KDE as a integrated desktop environment….