Push Notification via Telegram

Bis vor ca. zwei Wochen hatte ich mit dem Benachrichtigungsdienst Pushalot von Maciej Olesiński eine wirklich gute und verlässliche Plattform, um mir allerlei Statusmeldungen an zentraler Stelle zukommen zu lassen. Dann wurde es plötzlich ruhig auf meinen mobilen Endgeräten. Kein Server mehr, der mir seinem Gemütszustand mitteilte, keine Wohnungstür mehr, die mich über ihren Status informiert…
Inzwischen bin ich auch nicht mehr gänzlich allein mit dem Thema, wie man beispielsweise auf Reddit lesen kann. Das beruhigt ein wenig, da es nicht an mir zu liegen scheint, andererseits löst es aber auch das Problem nicht.

TelegramPushNotificationsWie dem auch sei – diesem Umstand geschuldet habe ich mich kurzerhand mit der API des Messenger-Dienstes Telegram befasst und entschieden, den Messenger für meine Zwecke und damit als Ersatz für die ausbleibenden Benachrichtigungen von Pushalot zu verwenden.
Die API ist überaus funktional, reich an Funktionen und durchgehend gut dokumentiert. Der Service lässt sich unkompliziert über die heute gängigen Wege ansprechen.
Spannend ist das Konzept der Telegram-Bots als unpersonalisierte Service-Accounts, mit denen man in seiner Rolle als Nutzer interagieren kann. Dabei können vorhandene genutzt oder individuelle, neue Bots angelegt werden. Telegram geht diesen Weg sehr konsequent, so dass ebenfalls die Bedienung der Plattform auf Ebene des Entwicklers über einen solchen Bot läuft. Will man einen Bot erstellen und konfigurieren, so chattet man mit dem @BotFather, dem man über definierte Kommandos die entsprechenden Einstellungen übergibt bis hin zum Profilfoto des eigenen Bots.

Mit relativ geringem Aufwand haben in den letzten Tagen die beiden im vergangenen Jahr veröffentlichten Tools – der Homematic Notification Service sowie das PushMonitoring – einen zusätzlichen Benachrichtigungskanal für die Nutzung von Telegram erhalten.

Das Setup…

…der beiden Tools für die Verwendung der Telegram-Bots funktioniert wie folgt:

  1. Telegram installieren
  2. Als Empfänger die eigene Chat-ID herausbekommen
    (z.B. dem Bot @get_id_bot eine Nachricht mit /my_id senden)
  3. Die Chat-ID in der Konfiguration des Service/Tools ( <notifyBy /> bzw. <sendTo />) hinterlegen
  4. Den jeweiligen Bot – „Homematic Alert“ bzw. „PushMonitoring“ – aufrufen und mit der Nachricht /start aktivieren

Homematic Notification Service

<notifyBy NotifyProvider="Telegram">123456789</notifyBy>

PushMonitoring

  <sendInterfaces>
    <sendTo Type="Telegram" ApiKey="123456789" />
  </sendInterfaces>

Alternativ können statt der eigenen Chat-ID noch Gruppen-IDs öffentlicher Gruppen verwendet werden, wenn der Bot in der Gruppe Mitglied ist.

Die Push-Messages, die über die beiden Tools versendet werden verhalten sich wie normale Chat-Nachrichten, die man vom Kontakt des jeweiligen Bots erhält:

TelegramPushWindowsPhone

Es ist ein wenig schade, dass Pushalot so ganz ohne weitere Informationen abgetaucht ist. An dieser Stelle vielen Dank an die Plattform und ihren Betreiber für die lange Zeit an Zuverlässigkeit sowie das kostenfreie Angebot!

Die beiden Tools (Homematic Notification Service + PushMonitoring) gibt es in aktualisierter Version an der üblichen Stelle im OneDrive oder den Quellcode unter GitHub.

Win32 oder .NET in UWP-App konvertieren

Bestehende Windows Desktop-Anwendungen mit nur wenig Kenntnis der UWP-Apps in eine vollwertige Windows 10 App konvertieren. Dieses Ziel hat man sich bei Microsoft mit dem Projekt Centennial gesetzt.
Der auf der Build 2016 vorgestellte Desktop App Converter war bereits vor einigen Monaten als Preview zum Download zu haben.

Der Konverter führt die Desktop-Anwendung bzw. deren Installer in einer isolierten Windows-Umgebung aus, welche dem Konverter als Windows Basis-Image beiliegt. Dabei werden alle Aktionen in Registry und Dateisystem erfasst und als Grundlage für ein neues AppX-Package verwendet. Diese UWP-App verfügt über ihre eigene Identität, was für die Verwendung der WinRT-APIs sowie die Integration von Features wie Live-Toasts, -Kacheln, Hintergrundaufgaben und Ähnliches erforderlich ist.

Microsoft sieht für Entwickler, die sich mit dem Schwenk auf die neue Plattform schwer tun, einen fließenden Migrationsprozess vor. Zuerst soll die Portierung auf die UWP-App per Konverter erfolgen. Nach dem Bereitstellen und Testen der App könne man UWP-Features ergänzen und die Anwendung Schritt für Schritt optimieren. Zu guter Letzt soll die UWP-App dann für alle Windows-Zielplattformen portiert werden können.

Vor ein paar Tagen gab es eine neue Version v0.1.21 im Downloadbereich inklusive der Windows Base Images 14371 und 14372. Einen guten Einstieg ins Thema bietet die Dokumentation des Konverters.

Ich wage zu bezweifeln, dass dies den mit großer Wahrscheinlichkeit erhofften Durchbruch für die Windows Apps bringen wird, bin aber gespannt, ob der Konverter eine echte Alternative gegenüber dem manuellen Portieren ist und einen entsprechenden Mehrwert bietet. Sollte dem so sein, werde ich ganz sicher ein wenig ausführlicher darüber berichten.

ListItem-Update führt zu „Catastrophic failure“

In einer SharePoint Liste ohne EventReceiver mit einem nicht angepassten Standardformular meldet das System beim Versuch ein Listenelement zu aktualisieren Folgendes:

Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

Neben der doch sehr drastischen Wortwahl deutet bereits das HRESULT auf eine durchgereichte COM-Exeption hin. Gerade bei solch vermeintlich tiefgreifenden Offenbarungen erhält man üblicherweise den bekannten, ganzseitigen Dialog mit der beschwichtigenden Entschuldigung, etwas hätte leider nicht geklappt. Nicht so hier. Die Meldung erscheint ohne viel Drumherum und ohne Korrelationsid in roten Lettern direkt unterhalb der Angaben zu Erstellt/Geändert und dem Speichern-Button.
Das Anlegen von Listenelementen in besagter Liste funktioniert weiterhin problemlos – nur unangenehmerweise das Update nicht mehr.

Ein Blick ins ULS (Methodensignaturen auf das Wesentliche gekürzt) gibt ein wenig mehr Informationen preis:

Original error: Microsoft.SharePoint.SPException: Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) 
---> System.Runtime.InteropServices.COMException: Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))    
 at Microsoft.SharePoint.Library.SPRequestInternalClass.AddOrUpdateItem( /* --- snip --- */ )    
 at Microsoft.SharePoint.Library.SPRequest.AddOrUpdateItem( /* --- snip --- */ )     -
-- End of inner exception stack trace ---    
 at Microsoft.SharePoint.SPGlobal.HandleComException(COMException comEx)    
 at Microsoft.SharePoint.Library.SPRequest.AddOrUpdateItem( /* --- snip --- */ )    
 at Microsoft.SharePoint.SPListItem.AddOrUpdateItem( /* --- snip --- */ )    
 at Microsoft.SharePoint.SPListItem.UpdateInternal( /* --- snip --- */ )    
 at Microsoft.SharePoint.SPListItem.Update()    
 at Microsoft.SharePoint.SPListItem.ValidateUpdateListItem_Client( /* --- snip --- */ )    
 at Microsoft.SharePoint.ServerStub.SPListItemServerStub.InvokeMethod( /* --- snip --- */ )    
 at Microsoft.SharePoint.Client.ServerStub.InvokeMethodWithMonitoredScope( /* --- snip --- */ )

Hier erfährt man, wo die Exception geworfen wurde. Leider führt auch mit diesen detaillierteren Angaben eine Suche im Netz schnell in die Irre, was mir Grund und Anlass für diesen kurzen Post sein soll.
Gut gemeinte Tipps wie „iisreset“ oder „Liste löschen und neu anlegen“ über „Entfernen von Inhaltstypen lowlevel in der Config-DB“ bis hin zu „ein ernstzunehmendes Problem mit möglicherweise korrupten DLLs und man möge den 0x8000FFFF bitte nicht auf die leichte Schulter nehmen“ waren dabei nicht ernsthaft vielversprechend. Lediglich ein Hinweis auf einen Schreibfehler einer Feldbezeichnung in der Schema.xml hatte Potential.

Was ich noch erwähnen sollte: Die Liste ist Teil einer per WSP im SharePoint ausgerollten Solution mit deklarativ definierten Listen.

Die Lösung

Da es recht sicher war, dass der Fehler im Zusammenhang mit der Listendefinition stehen musste, schien die Eingrenzung des Fehlers sinnvoll. Durch das Löschen aller benutzerdefinierten Felder der Liste, bis ein Update wieder möglich war, konnte als Übeltäter ein Auswahlfeld (Choice-Field) identifiziert werden. Mit einem von Hand auf der Liste angelegten Feld gleichen Namens und Typs bestand das Problem nicht länger.

Die genaue Untersuchung der Feld-Definition in der Schema.xml der zugrundeliegenden Liste brachte die Ursache ans Licht.
Im Field-Element des Auswahlfelds war das optionale Attribut BaseType mit dem Wert  „Integer“ enthalten, mit welchem man explizit angeben kann, ob der Wert als Integer oder als Text persistiert werden soll.

In der Beschreibung des Attributs im Artikel der MSDN ist ersichtlich, dass die Verwendung des BaseTypes in Zusammenhang mit Choice- bzw. Auswahlfeldern nicht möglich ist:

BaseType | Optional. The BaseType attribute can be set to Integer, which stores values as integers, or to Text (default), which stores values as text. You cannot create integer base-type choice fields.

Dennoch spannend, dass sich ein dementsprechend definiertes Feld in einer Liste überhaupt anlegen und ein Listenelement damit erstellen lässt sowie dass dazu noch die eher spektakuläre, wenig sagende Fehlermeldung präsentiert wird.
Falls irgendjemand mal Lust hat herauszubekommen, warum ausgerechnet für Auswahlfelder die Option Integer nicht zulässig ist – ich würde mich über eine Antwort freuen.

SharePoint Bulk-Delete via PowerShell

1.000+ ListItems in einer SharePoint-Liste und die müssen alle weg – und zwar fix. Manchmal sind es Demo- oder Test-Daten und mal soll schlicht nur aufgeräumt werden. Was tun? Eine Art „TRUNCATE TABLE“ wäre schön. Wieder hilft hier die PowerShell mit wenigen Zeilen und geladenen SharePoint-Commandlets weiter.

DELETE ALL ListItems

$web = Get-SPWeb <URL zum Web>
$lst = $web.Lists[„<Name der Liste>“]
$lst.Items | % { $lst.GetItemById($_.ID).Delete(); }

Zwar muss man dediziert für jedes ListItem die Delete-Methode rufen doch dafür verschwinden so zügig und unkompliziert die nicht länger benötigten Elemente aus SharePoint-Listen oder Bibliotheken.

Noch etwas interessanter wird der auf den ersten Blick nicht übermäßig elegant anmutende Ansatz für ein selektives Massen-Löschen…

DELETE SOME ListItems

$web = Get-SPWeb <URL zum Web>
$lst = $web.Lists[„<Name der Liste>“]
$query = New-Object Microsoft.SharePoint.SPQuery
$query.Query = „<Where><Eq><FieldRef Name=’Project‘ LookupId=’TRUE‘ /><Value Type=’Lookup‘>23</Value></Eq></Where>“
$lst.GetItems($query) | % { $lst.GetItemById($_.ID).Delete(); }

Mit Hilfe einer CAML-Abfrage holt man sich nur die ListItems, die man löschen möchte. Auf dem SPList-Objekt findet man die Methode GetItems(), welches als Parameter ein SPQuery-Objekt entgegennimmt. Im Beispiel oben sind ListItems zu löschen, die mit einem Projekt-Datensatz in einer zweiten Liste verknüpft sind, welcher auf die ID 23 hört.

Wer nun Freude am Löschen per PowerShell findet, für den habe ich hier noch ein paar CAML-Query Beispiele zusammengetragen, welche vielleicht die ein oder andere Idee zur eigenen Adaption bringt…

# ** Query-Beispiel: ListItems, deren ID kleiner als 250 ist
$query.Query = „<Where><Lt><FieldRef Name=’ID‘ /><Value Type=’Counter‘>250</Value></Lt></Where>“

# ** Query-Beispiel: ListItems, die am oder nach dem 01.01.2016 angelegt wurden
$query.Query = „<Where><Geq><FieldRef Name=’Created‘ /><Value IncludeTimeValue=’FALSE‘ Type=’DateTime‘>2016-01-01</Value></Geq></Where>“

# ** Query-Beispiel: ListItems, die im Titelfeld mit ‚A‘ beginnen
$query.Query = „<Where><BeginsWith><FieldRef Name=’Title‘ /><Value Type=’Text‘>A</Value></BeginsWith></Where>“

# ** Query-Beispiel: ListItems, deren Beschreibungsfeld (‚Description‘) das Wort ‚Prozess‘ enthält
$query.Query = „<Where><Contains><FieldRef Name=’Description‘ /><Value Type=’Note‘>Prozess</Value></Contains></Where>“

# ** Query-Beispiel: ListItems, deren Aktiv-Flag auf FALSE gesetzt ist
$query.Query = „<Where><Eq><FieldRef Name=’Active‘ /><Value Type=’Boolean‘>0</Value></Eq></Where>“

Und wem das nicht weit genug geht – man kann nicht nur die Delete-Methode auf dem Objekt rufen…

LED Strip Connector mit eigenem Kabel anschließen

Heute mal thematisch etwas ganz anderes aus der Kategorie „Basteln“. Niedervolt LED-Strips haben hervorragende Eigenschaften, um mit minimalem Aufwand als Hintergrundbeleuchtung verbaut zu werden. Die Installation ist denkbar einfach und das Anschließen der Stromversorgung ist selbst für Hobby-Handwerker keine echte Herausforderung, wenn die Strips nicht gerade im Sichtfeld montiert werden sollen und man die passenden Verbinder zur Hand hat.

Kürzlich hatte ich das Problem, dass ich LED-Strips anschließen wollte, bei denen aus ästhetischen Gründen der Anschluss direkt in ein weißes Kabel übergehen sollte, welches ich sichtbar aber dezent am Türrahmen verlegen wollte. Im Lieferumfang fanden sich ein dickes, schwarzes Kabel mit vergossener Sockel-Buchse, eine etwas dünnere und angelötete Doppellitze in Rot und Schwarz sowie zwei Schnellverbinder, mit denen man hätte zwei Strips verbinden können. Grundsätzlich ausreichend – in meinem Fall allerdings keine brauchbaren Optionen, wenn nicht von den Türrahmen schwarze Kabelpeitschen mit Steckern baumeln sollten.

So fiel meine Wahl auf die Schnellverbinder, die eigentlich nicht zum Anschluss der Stromversorgung gedacht waren. Bleibt die Frage: Wie die Litze so einklemmen, dass sie auch nach dem Schließen des Schnellverbinders noch ausreichend Kontakt gibt, keinen Kurzschluss macht und nicht verrutscht?

LED-con_before

Nach einigen erfolglosen Versuchen, war ich bereits fast willens die Anschlüsse direkt auf die LED-Strips zu löten. Da kam mir die Idee, direkt aus den Kabelenden einen Verbinder zu formen, der unter die beiden Kontakte passt und nicht verrutscht.

LED-con_prep1

Die von der Isolierung befreiten Enden zog ich etwas auseinander, so dass die Litze ein flaches und breites Bündel bildete (1). Anschließend verzinnte ich die Bündel mit ausreichend Flussmittel (2). Trotz des vorherigen Auseinanderziehens waren die Enden noch viel zu dick, um unter die Kontakte zu passen.

LED-con_prep2

Um die Enden nun entsprechend flach zu formen, presste ich die Enden mit Hilfe eines Feinmechaniker-Schraubstocks auf die benötigte Stärke, in etwa einen viertel Millimeter und schnitt anschließend überschüssiges Material ab, um die Kontaktflächen zu bilden (3). Wer keinen Schraubstock zur Hand hat, könnte auf eine ausreichend starke Zange, Schraubzwingen oder im Notfall auch auf einen Hammer zurückgreifen. Um nun unter den Kontakten nicht zu verrutschen, hilft noch eine leichte Körnung in der Mitte der entstandenen Kontaktfläche (4).

Das Ergebnis erfüllt seinen Zweck und ist in jedem Fall eine Alternative, wenn man gerade kein passendes Anschlussmaterial sondern nur den Schnellverbinder bei der Hand hat.

LED-con_after

Sicherheitshalber noch der Hinweis, dass sich diese Art des Anschlusses lediglich für feste, nicht bewegte Installationen sowie für die 2-Pin-Variante sinnvoll anbietet, da nur der zweipolige Schnellverbinder (10mm) über ausreichend Platz zur Aufnahme der gelöteten Kontaktflächen bietet.
Obwohl auf Grund der geringen Spannung die Luftstrecke vernachlässigbar ist, sollte ein Abstand von mindestens einem Millimeter zwischen den Kontakten eingehalten werden, um Fehler zu vermeiden. Und zu guter Letzt: Jeder bastelt auf eigene Verantwortung. Gewissenhaftes Arbeiten bei der Herstellung und Klemmung der Kontakte ist dementsprechend wichtig – wer sich unsicher ist, sollte auf Anschlussmaterial der Hersteller zurückgreifen.

RSSharePointList-CAML-Hacks

Möchte man mit wenig Aufwand auf SharePoint-Listen mit Hilfe der SQL Server Reporting Services zugreifen, so kommt man am Datenquellen-Verbindungstyp für SharePoint-Listen nicht vorbei.
Dieser Verbindungstyp, auch bekannt als RSSharePointList bzw. SharePoint List Connection Type (Data Extension/Data Provider), ermöglicht einen einfachen Zugriff auf einzelne SharePoint-Listen eines SharePoint-Webs.

rssplist_smpl1

Konkret wird dabei ein SharePoint-Web bzw. eine SiteCollection mit einer SSRS-DataSource abgebildet, wohingegen ein SSRS-DataSet eine SharePoint-Liste repräsentiert.

rssplist_smpl2

Mittel eines Abfrageassistenten, der alle Listen/Bibliotheken eines Webs auflistet und darin enthaltene Spalten für das zu erstellende DataSet zur Auswahl anbietet, ist eine Definition der Reportdatenquelle schnell zusammengeklickt.

rssplist_smpl3

Heraus kommt eine XML-Struktur, eingeleitet mit dem Tag <RSSharePointList>, welches dem Entwickler mit SharePoint-Erfahrung bereits vertraut vorkommen könnte. Spätestens dann, wenn man noch eine Abfragebedingung im Assistenten hinzufügt, sind die Parallelen zu CAML, der in der SharePoint-Welt gängigen Collaborative Application Markup Language, nicht zu leugnen.

So weit, so gut. Solange man mit dem auskommt, was der Abfragedesigner zu leisten vermag, ist der BI-Analyst zufrieden. Letztendlich ist das oben Beschriebene ein alter Hut und die Nachfolgetechnologien stehen lange in den Startlöchern. Dennoch – SSRS und SharePoint sind auch 2016 noch ein Thema und es gibt Situationen, in denen man schneller als erwartet an Grenzen stößt. Ganz besonders dann, wenn man an den Komfort von der Flexibilität von SQL-Statements gewohnt war, um die Daten in eine für den Report sinnvolle Form zu bringen.

Hier wird es eng…

  • Sortieren von DataSets bereits zur Abfrage (Äquivalent zum SQL ORDER BY)
  • Arbeiten mit Referenzen auf andere SharePoint-Listen bzw. Listenelemente
  • Arbeiten mit Referenzen aus MultiValue-Lookups

Das grundlegende Problem wird bereits im Abfragedesigner deutlich. Eine Abfrage, ein DataSet. Sobald eine zweite Liste ausgewählt wird, erinnert eine Messagebox daran, dass die bisherige Auswahl verworfen wird. In nativem CAML wären JOINs möglich – nicht so mit RSSharePointList. Benötigt man nun Daten des referenzierten Datensatzes aus einer zweiten Liste, ist man darauf angewiesen, die zweite Liste ebenfalls als DataSet einzubinden und mittels Lookup-Funktion der Reporting Services dort einzelne Spalten abzuholen. Dies wird zudem noch erheblich erschwert, dass man mit dem Anzeigenamen des referenzierten Datensatzes und nicht mit der ID arbeiten muss, dass die ID hinter dem SharePoint Lookup-Feld nicht im DataSet erscheint.

Hier kommt man weiter…

Sortieren

Glücklicherweise ist im Rahmen von Berichtselementen wie Diagrammen oder Tabellen bzw. Tabellengruppen das Sortieren vorgesehen, so dass man selten die Notwendigkeit hat, dies bereits zur Abfragezeit zu berücksichtigen. Bei Parametern allerdings, deren Daten auf einer Abfrage basieren, ist dies der einzige Weg, da das DataSet selbst keine Sortierung kennt.
Da uns die Ähnlichkeit zu CAML aufgefallen ist, ist es naheliegend das Sortier-Konstrukt aus eben dieser Notation im SSRS Data Provider zu testen. Unterhalb des Query-Elements kann man das OrderBy-Element verwenden…

<RSSharePointList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ListName>SortTest</ListName>
  <ViewFields>
    <FieldRef Name="Title" />
    <FieldRef Name="Category" />
    <FieldRef Name="DueDate" />
    <FieldRef Name="ID" />
  </ViewFields>
  <Query>
    <OrderBy>
      <FieldRef Name="Category" />
      <FieldRef Name="DueDate" Ascending="FALSE" />
    </OrderBy>
  </Query>
</RSSharePointList>

Referenzen

Hat man innerhalb von SharePoint seine Datenstrukturen rein relational und vollständig 1:n aufgebaut, sprich ohne die Verwendung von Multi-Lookup-Spalten, so will man häufig nur eine Liste anhand einer ID filtern, die aus z.B. einem Report-Parameter stammt oder einem Übergabeparameter für einen Sub-Report dient.
Im Standard kommt man mit der allerdings nicht besonders weit, denn das Where-Element enthält nur einen einfachen, String-basierten Vergleich, der lediglich das Filtern auf Anzeigenamen ermöglicht. Sicherlich ist dies eine Alternative, solange der Titel sich nie ändert und über die gesamte Zeit eindeutig ist. Von diesen idealen Bedingungen kann man aber nicht immer ausgehen.
Ein einfacher Trick aus der CAML-Welt hilft hier weiter: Das Setzen des Attributs LookupId auf TRUE am FieldRef-Element im Query ermöglicht das Nachschlagen per ID.

<RSSharePointList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ListName>Task</ListName>
  <ViewFields>
    <FieldRef Name="Title" />
    <FieldRef Name="ProjectName" />
    <FieldRef Name="ScheduledDate" />
    <FieldRef Name="ActualDate" />
    <FieldRef Name="ID" />
  </ViewFields>
  <Query>
    <Where>
      <Eq>
        <FieldRef Name="ProjectName" LookupId="TRUE" />
        <Value Type="Lookup">
          <Parameter Name="ProjectId" />
        </Value>
      </Eq>
    </Where>
  </Query>
</RSSharePointList>

Innerhalb von Listen mit Referenzen auf andere Listen steht man vor einem ähnlichen Problem. Möchte man hier die ID zum referenzierten Datensatz erhalten, hat man nur den zum Nachschlagefeld definierten DisplayName. Dieser hilft ebenfalls nur unter idealen Bedingungen weiter und dürfte sich nie ändern. Und auch hier: Entgegen der CAML-Dokumentation führt das LookupId-Attribut am FieldRef-Element im ViewFields-Element zum Erfolg.

<RSSharePointList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ListName>Task</ListName>
  <ViewFields>
    <FieldRef Name="Title" />
    <FieldRef Name="ProjectName" LookupId="TRUE" />
    <FieldRef Name="ScheduledDate" />
    <FieldRef Name="ActualDate" />
    <FieldRef Name="ID" />
  </ViewFields>
</RSSharePointList>

…leider mit der Einschränkung, dass man sich für ID oder DisplayName des Lookups entscheiden muss.

…und hier hört es auf

  • CAML-Join
  • CAML-Group
  • CAML-RowLimit
  • Multi-Lookup Columns

rssplist_failed

Frohes Reporten weiterhin!

Homematic Notification Service

Ganz heimlich, still und leise hatte ich hier an dieser Stelle zum vergangenen Weihnachtsfest ein Stückchen Software in die große, weite Welt entlassen und nicht viele Worte darüber verloren: den Benachrichtigungsdienst für die Homematic CCU2.

Wofür dieser Benachrichtigungsdienst gut ist, ist schnell erklärt. Wer ein Heimautomatisierungssystem aus der Produktion der eQ-3 AG sein Eigen nennt, hat oft mehr als nur zeitgesteuerte Beleuchtung oder Heizungsregelung im Sinn. Ist man nicht zu Hause, ist eine Alarmschaltung oder ein Monitoring der Rauchmelder nützlich. Leider ist die Einrichtung einer zeitgemäßen Benachrichtigung über Änderungen von Schaltzuständen, zum Beispiel beim Öffnen einer Tür oder Erkennung von Bewegung über einen Bewegungsmelder, mit Bordmitteln nicht ganz trivial zu realisieren und mündet gelegentlich in eine instabile oder hängengebliebene CCU2. Um hier Abhilfe zu schaffen, habe ich mir zum Thema ein paar Gedanken gemacht und eine einfache Dienstanwendung gebastelt.

Das eigentliche Highlight ist die Möglichkeit zu haben, sich bei wichtigen Ereignissen per Push-Message direkt auf das Handy benachrichtigen zu lassen – hier im Beispiel die App Pushalot unter Windows 10 sowie auf dem Handy unter Windows Phone 8.1:

Die Anwendung ist als Windows-Dienst implementiert, versendet Benachrichtigungen für Ereignisse der per Konfiguration angegebenen Homematic-Sensoren und protokolliert auftretende Fehler im Eventlog. Kurz gesagt: reine Backend-Logik. Um dennoch die Funktion der Anwendung sowie der erstellten Konfigurationsdatei testen zu können, gibt es zusätzlich eine Windows-Forms Applikation, die sowohl die aus der Konfiguration ausgelesenen Einstellungen und Benachrichtigungselemente darstellen kann, als auch auszuführende Benachrichtigungen versendet/simuliert und Fehler protokolliert.

HomeMaticNotification_TST

Die Basiskonfiguration (Pfad zur Konfigurationsdatei, Ausführungsintervalle, etc.) des Dienstes oder auch der Anwendung ist in der jeweiligen App-Config „SVC_HomeMaticNotification.exe.config“ zu finden. Die wesentlich wichtigere, inhaltliche Konfiguration wie Benachrichtigungsgruppen, Benachrichtigungsziele sowie die zu überwachenden Geräte sind in einer separaten XML-Konfigurationsdatei zu konfigurieren.

HMN_SampleConfig

Um nicht nur einen Empfänger von einer Dienst-Instanz zu benachrichtigen, können parallel mehrere Gruppen von Benachrichtigungen (notifyGroup) mit unterschiedlichem Umfang, Einstellungen und Empfänger hinterlegt werden. Pro Gruppe kann ein Benachrichtigungsziel (notifyBy) festgelegt werden, was entweder ein Key der Push-Dienste Pushalot (NotifyProvider=“Pushalot“) oder Pushover (NotifyProvider=“Pushover“) sein kann oder auch eine E-Mail-Adresse (NotifyProvider=“Email“).
Für ein Benachrichtigungselement (notifyItem), ein per Device-Serial adressiertes Gerät, können erweiterte Einstellungen konfiguriert werden, so dass beispielsweise zu festgelegten Tagen/Uhrzeiten (silenceTimes/silence) oder bei dem Zutreffen bestimmter Bedingungen (conditions), wie Schaltzuständen weiterer Geräte (devCondition) bzw. Systemvariablen der Homematic-Zentrale (varCondition), Benachrichtigungen nicht übermittelt werden dürfen.

Das Monitoring der Homematic-Komponenten erfolgt in der vorliegenden Version nicht wirklich ereignisgesteuert, sondern bedient sich einem design-technisch nicht allzu schönem Workaround, der dies lediglich so erscheinen lässt. Allem voran die in meinem letztjährigen Post zum Thema erwähnten Schwierigkeiten mit der Eventregistrierung über die native Schnittstelle der CCU2, XML-RPC, führten dazu, dass ich ein – in der Standardkonfiguration zwei-sekündlich – „pollendes“ Verfahren für die Überwachung der Komponenten verwende. Auch wenn ich inzwischen teilweise die ursprünglichen Probleme umgehen konnte, hatte ich dennoch mit erhöhtem Stromverbrauch der abgefragten Sensoren/Aktoren zu kämpfen. Hinzu kommt, dass ich zu Beginn der Entwicklungsarbeiten am Dienst auf die HomeMatic-XmlApi-Lib zurückgreifen musste, so dass ein Rückportieren auf XML-RPC aus heutiger Sicht nicht lohnenswert erscheint. Die sehr häufige Abfrage der XML-API (~40k Requests/Tag) scheint keine negative Auswirkung auf die CCU2 zu haben – der Service läuft bei mir ca. seit einem Jahr sehr stabil ohne auffällige Probleme oder Unzuverlässigkeit.

Im aktuellen Release (v1.1.9.3) sind inzwischen ein paar neue Funktionen enthalten sowie ein paar Bugs korrigiert. Für alle Interessierten steht die Software (inkl. Tester-Anwendung und Beispielkonfiguration) in meinem OneDrive zum Download bereit. Die jeweils neuste Version wird als Quellcode im dazugehörigen Repository auf Github zu finden sein.

HomeMaticNotification_TSTGitHub-Repo: github.com/roschinsky/HomeMatic-Notification-Service

MD5 Hash: ca29cbe561e53507db4feca121454af6


Feedback, Forks oder interessante Fragen – hier oder auf Github – sind stets willkommen.

Für die Zukunft ist geplant die Dienstanwendung auf den RaspberryPi zu portieren, so dass sie unter Windows 10 for IoT lauffähig ist.

Folgen

Erhalte jeden neuen Beitrag in deinen Posteingang.

Schließe dich 178 Followern an