Amazon Dash Button als Homematic Schalter

Kürzlich hat Amazon die Dash Buttons hier in Deutschland vorgestellt. Kleine, kostengünstige (kostenneutrale) Knöpfe, die sich per WLAN mit Amazon verbinden wollen und vorkonfiguriert ein Produkt bestellen.

Inspiriert von dieser Seite dachte ich mir, dass man doch den Dash Button auch verwenden können müsste um als Homematic Schalter / Sensor zu dienen.
Im ersten Schritt wäre also ein Raspi zu nehmen der mittels Python auf die ARPProbes des Dash Buttons lauscht und bei Gelegenheit einen HTTP-GET auslöst um ein Programm in der CCU per XMLAPI zu starten.

Klappt auch wunderbar – ganz ähnlich zu der Seite oben:

  1. Vorbereitung: Der Dash Button muss sich mit dem WLAN verbinden können, aber kein Produkt bestellen: Dafür nimmt man die Amazon App auf dem Handy und richtet den Button ein, bis man zur Produktauswahl kommt. Dann aber kein(!) Produkt wählen, einfach abbrechen.
  2. MAC Adresse des Buttons rausbekommen: Im Netz findet man diverse Tools dafür – was bei mir aber nicht so recht klappen wollte. Vermutlich weil Laptop und Dash-Button in unterschiedlichen WLAN-Repeatern waren.
    Ich habe einfach meine Fritzbox gefragt, wer sich nach einem Druck auf den Dash-Button eingelogged hat. Mittels System -> Ereignisse -> aktivieren von „Auch An- und Abmeldungen protokollieren“ geht das ganz einfach, wenn man eine Fritzbox hat.
  3. Dann habe ich das Skript dash-listen-2.py von dort genommen und habe einfach nach einem print anweisung noch einen entsprechenden http-get Befehl auf meine CCU mit XMLAPI eingefügt – ungefähr so:oben einfügen:
    import urllib2

    und an der Stelle, wo auch die Print ausgaben anzeigen, dass ein Button erkannt wurde:

    urlopen("http://homematic/config/xmlapi/runprogram.cgi?program_id=MEINEPROGRAMMID").read()

     

Das wars schon – sobald der Button sich per verbindet, setzt er ein ARPProbe ab, was detektiert wird und – in meinem Fall – das Programm zur Gartenbewässerung startet.

 

Wenn jemand eine Idee hat, die das Überprüfen auch direkt auf der CCU mittels z.B. TCL gehen könnte: Bitte melden!

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 🙂