Hue Programmierung via REST – Teil 2

Nachdem wir jetzt den API-Schlüssel erstellt haben, können wir ihn zur Abfrage der Konfiguration nutzen. Dazu geht man auf die /debug/clip.html Seite und trägt unter URL /api/#Schlüssel# ein. Nach dem Drücken des GET Buttons erhält man dann im Command Response Fenster die Ausgabe, die aus JSON-Teilen für Lampen, Gruppen und der Konfiguration besteht. Da ich einige Lampen und Gruppen habe, kommen bei mir etwas über 5000 Zeilen zurück.

Die JSON-Struktur ist hierarchisch aufgebaut, durch leichte Anpassungen der URL kann man auf die einzelnen Teile der Konfiguration zugreifen, so erhält man durch

  • /api/#Schlüssel#/lights den Abschnitt mit den Lampen
  • /api/#Schlüssel#/lights/1 den Abschnitt von Lampe 1
  • /api/#Schlüssel#/groups den Abschnitt mit den Gruppen
  • /api/#Schlüssel#/config die Systemkonfiguration

Lampen steuern

Um jetzt einzelne Eigenschaften wie an/aus, Helligkeit und Farbe zu setzen, müssen wir per „PUT“ (nicht „GET“) entsprechende JSON-Schnipsel absenden. Das folgende Beispiel schaltet Lampe 9 aus:

  • URL:
    /api/#Schlüssel#/lights/9/state
  • Message Body:
    {"on":false}

und das folgende wieder an:

  • URL:
    /api/#Schlüssel#/lights/9/state
  • Message Body:
    {"on":true}

Hier jetzt noch das wichtigste Beispiel, das nicht nur an/aus kontrolliert, sondern auch Farbe und Helligkeit:

  • URL:
    /api/#Schlüssel#/lights/9/state
  • Message Body:
    {"on":true, "sat":254,"bri":254, "hue":30000}

Im nächsten Teil dieser Serie schauen wir uns dann an, wie die einzelnen Komponenten umgewandelt werden müssen, um die gewünschte Farbe und Helligkeit zu erhalten.

Hue Programmierung via REST – Teil 1

Der folgende Artikel und seine Folgeartikel sind für diejenigen gedacht, die ein Philips Hue System ihr Eigen nennen und ein wenig tiefer in die Programmierung einsteigen möchten. Grundvoraussetzung ist eine aktive Hue Bridge im lokalen Netz und mindestens eine gekoppelte Lampe.

In diesem Artikel erstellen wir einen neuen Api-Schlüssel, den wir für alle weiteren Experimente brauchen. In den Folgeartikeln zeige ich dann, wie man mittels Webinterface, CURL und Python entsprechende Befehle an die Hue Bridge senden kann.

Grundsätzliches

Die IP-Adresse der Hue Bridge bekommen wir über den Router raus, sofern wir sie nicht kennen, Philips selbst zeigt noch andere Wege. Ruft man diese IP-Adresse im Browser auf, so kommt nur die Webseite des Systems zusammen mit den Hinweisen auf die entsprechenden Opensource-Lizenzen, nichts sonderlich spannendes.

Spannender wird es allerdings, wenn man die IP-Adresse mit der URL /debug/clip.html aufruft. Dann nämlich präsentiert sich ein Formular mit mehreren Textfeldern und Buttons, die wir im Laufe der Artikel noch näher kennenlernen werden.

Drückt man den GET-Button, kommt die folgende Meldung zurück:

[
	{
		"error": {
			"type": 1,
			"address": "/",
			"description": "unauthorized user"
		}
	}
]

Der Hue Bridge fehlt also der entsprechende Authentifizierungsschlüssel, ohne den keine Befehle angenommen werden. Um einen solchen Schlüssel zu erstellen, geht man wie folgt vor:

  1. Drücke den Link-Button oben auf der Hue Bridge
  2. Gib in der URL Box /api ein
  3. Gib in der Message Body Box einen Text analog zum folgenden Muster ein

    {"devicetype":"commandline#Uwe"}. Ich habe hier einen Hinweis auf meine Kommandozeile als Namen gewählt, letztlich ist man hier aber recht frei. So nennt sich IFFT bei mir „ifft2“, der Logitech Harmony Hub heißt einfach „Harmony Hub“

Wenn alles geklappt hat, dann antwortet die Bridge mit einer Antwort analog zur folgenden:

[
	{
		"success": {
			"username": "yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxt"
		}
	}
]

Der zufällige String hinter username, hier unkenntlich gemacht, ist der entsprechende Schlüssel, den wir bei jeder Anfrage an die HUE Bridge mitliefern müssen. Es empfiehlt sich daher, den in einer Textdatei zu parken und keinesfalls zu veröffentlichen.

Using individual glyphs from a OpenType Font in LuaLaTeX

I am currently preparing a tutorial on the Texas Instruments BAII Plus Professional Calculator in LaTeX. TI provides the font for the different keystrokes as TTF and PFB/PFM which makes it way easier to typeset the symbols.

The first step was to convert the font to OTF format. I tried TTF 2 OTF first without luck as the resulting OTF did not have any symbols in it. Using PFB 2 OTF worked better, the generated OTF had supposedly all the keys in it.

In the next step I wanted to generate an LaTeX overview of all symbols. Using the information from https://tex.stackexchange.com/questions/103704/how-to-properly-install-and-use-a-new-font-with-lualatex and https://tex.stackexchange.com/questions/25249/how-do-i-use-a-particular-font-for-a-small-section-of-text-in-my-document/37251 I came up with the following (don’t forget to install the OTF before!):

\documentclass[11pt]{article}
 
\usepackage[left=1cm,right=1cm,landscape,a4paper]{geometry}
\usepackage{fontspec}
 
\newfontfamily\tifont{BA2Plus Symbols}
 
\usepackage{luacode}
\usepackage{longtable,array,xcolor,listings}
\begin{luacode*} 
function print_glyphs(maxCols,maxChars) 
  local id = font.current()         -- geht Font ID
  local fnt = font.getfont(id)
  local col = 1
  local maxU4 = 15*(16^3+16^2+16+1)
  a = {}
  for k, v in pairs(fnt.characters) do
    a [#a + 1] = k
  end
  table.sort(a)
  for i, k in ipairs(a) do
    if i >= maxChars then break end
    if col == 1 then
      if k > maxU4 then
        tex.sprint(string.format("U+%06x", k))
      else
        tex.sprint(string.format("U+%04x", k))
      end
      tex.sprint("&") 
    end
    if (i) then
      tex.sprint(string.format([[\char%i]], k))
    else
     tex.sprint("~")
    end
    if col == maxCols then              -- Line finished?
      tex.sprint([[\\\cline{2-]] .. maxCols+1 .. "} ")  -- Yes
      col = 1                           -- newline
    else
      tex.sprint("&")                   -- no, Print &
      col = col + 1                     -- next column
    end
  end
end
\end{luacode*}
 
 
\begin{document}
 
{\tifont
\begin{longtable}{>{\color{black!50}\ttfamily\footnotesize}r|
                  *{10}{>{\color{black}}p{5em}|}}
\cline{2-11}
\endhead
 
\directlua{print_glyphs(10,65463)} \\ \cline{2-11}
\end{longtable}}
 
\end{document}

PDF

The next step then was to create a logic of how to address the different symbols. Of course TSX was helpful again (https://tex.stackexchange.com/questions/38402/how-to-pick-a-specific-symbol-from-a-specific-font):

\documentclass[twocolumn]{article}
\usepackage{fontspec}
\usepackage[top=4cm,left=2cm,right=2cm,bottom=2cm]{geometry}
\newfontfamily\tifont{BA2Plus Symbols}
\newcommand\tif[1]{{\tifont\symbol{#1}}}
\usepackage{fonttable}
 
\begin{document}
\twocolumn
 
33  >  \tif{33}
 
34  >  \tif{34}
 
...
 
124  >  \tif{124}
 
125  >  \tif{125}
 
\end{document}

PDF

The next step is to come up with a convenient way of addressing the glyphs, e.g. by creating aliases for each glyph.

LaTeX Beamer Beispiel mit Metropolis und IBM Plex

Hier ein Beispiel für das Beamer Metropolis Theme mit IBM Plex Schrift:

\documentclass[12pt,ngerman]{beamer}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{booktabs}
\usepackage{babel}
\usepackage{graphicx}
\usepackage{csquotes}
\usepackage{xcolor}
 
 
\usepackage[sfdefault]{plex-sans}
\usetheme[progressbar=frametitle]{metropolis}           % Use metropolis theme
 
\title{A minimal Metropolis + IBM Plex example}
\date{\today}
\author{Max Mustermann}
\institute{The Name of the Institute}
 
\makeatletter
\setlength{\metropolis@titleseparator@linewidth}{1pt}
\setlength{\metropolis@progressonsectionpage@linewidth}{1pt}
\setlength{\metropolis@progressinheadfoot@linewidth}{1pt}
\makeatother
 
\begin{document}
 
\begin{frame}
	 \maketitle
\end{frame}
 
\begin{frame}
\frametitle{Introduction}
\framesubtitle{~}
 
\[ a^2 + b^2 = c^2 \]
 
\begin{itemize}
\item 
\item 
\item 
\item 
\item 
\item 
\end{itemize}
\end{frame}
 
\end{document}

Verlinkte Access Datenbanken umziehen lassen

Ich muss gelegentlich eine Access-Datenbank umziehen lassen, die auf diverse verlinkte Datenbanken zugreift (um das 2 GB Maximum zu umgehen). Da die Verlinkungen absolut sind und nicht relativ, muss man jede Verlinkung nach dem Umzug manuell anpassen, was bei mehr als 100 Tabellen mühselig und fehlerträchtig ist. Basierend auf Code von Stackexchange/Stackoverflow habe ich daher ein paar Hilfsfunktionen gebaut, die den Umzug deutlich vereinfachen. Die Annahme

Der Code besteht aus mehreren Funktionen:

  • getDatabaseName() extrahiert den Namen der Datenbank aus dem Pfad
  • GetFolder()
  • fragt beim Nutzer den Pfad ab, in dem die neuen Datenbank-Dateien liegen.

  • verlinkeTabellenNeu() biegt die Links auf die Datenbankdateien um

Hinweis: Es empfiehlt sich nach Abschluss ein Auslesen aller Verlinkungen und Abgleichen z.B. in Excel, um auf Nummer sicher gehen zu können, dass alle Verlinkungen erfolgreich waren. Zum Auslesen der Verlinkungen kann man den Code unten am Ende des Artikels nutzen.

Option Compare Database
 
Function getDatabaseName(currentPath As String)
    ' Uwe Ziegenhagen, 2017-11-03
    ' Extrahiert den Namen der Datenbank aus dem Pfad,
    ' wertet dazu die Position des letzten "\" aus:
    ' von innen nach außen:
    ' kehre String um
    ' finde den letzten Backslash
    ' nimm den substring bis zum letzten Backslash
    ' reverse diesen Substring wieder
 
getDatabaseName = StrReverse(Left(StrReverse(currentPath), InStr(StrReverse(currentPath), "\") - 1))
 
End Function
 
Function GetFolder() As String
' https://stackoverflow.com/questions/26392482/vba-excel-to-prompt-user-response-to-select-folder-and-return-the-path-as-string
' based on https://www.ozgrid.com/forum/forum/help-forums/excel-general/126180-getfolder-function?t=182343
 
' requires references to Microsoft Office xx.0 Object library
    Dim fldr As FileDialog
    Dim sItem As String
    Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
    With fldr
        .Title = "Select a Folder"
        .AllowMultiSelect = False
        '.InitialFileName = Application.DefaultFilePath
        If .Show <> -1 Then GoTo NextCode
        sItem = .SelectedItems(1)
    End With
NextCode:
    GetFolder = sItem
    Set fldr = Nothing
End Function
 
Sub verlinkeTabellenNeu()
' Uwe Ziegenhagen, 2017-11-03
' Ruft vom User einen Pfad ab und verlinkt alle Tabellen mit diesem Pfad neu
' based on code from https://stackoverflow.com/questions/4928134/changing-linked-table-location-programatically
 
ordnerNeu = GetFolder()
Dim dbs As DAO.Database
Dim tdf As DAO.TableDef
Set dbs = CurrentDb()
 
    With dbs
        For Each tdf In .TableDefs
        'Is the table a linked table?
            If tdf.Attributes And dbAttachedODBC Or tdf.Attributes And dbAttachedTable Then
                With tdf
                    oldPath = .Properties("Connect").Value
                    .Connect = ";DATABASE=" & ordnerNeu & "\" & getDatabaseName(.Properties("Connect").Value)
                    .RefreshLink
                    Debug.Print oldPath & "@@@" & .Properties("Connect").Value
                End With
            End If
        Next tdf
    End With
 
End Sub

Code zum Auslesen der Verlinkungen

Sub LinkedTableConnection()
' http://p2p.wrox.com/access-vba/37117-finding-linked-tables.html
   Dim dbs As DAO.Database
   Dim tdf As DAO.TableDef
 
   Set dbs = CurrentDb()
 
    With dbs
        For Each tdf In .TableDefs
        'Is the table a linked table?
            If tdf.Attributes And dbAttachedODBC Or tdf.Attributes And dbAttachedTable Then
                With tdf
                    ' Connect property contains path of link
                    ' Debug.Print "Connect Property of " & .Name & " is: " &  .Properties("Connect").Value
                    Debug.Print "kompletter Pfad: " & tdf.Connect
                    ' Debug.Print "Name der Datenbank: " & getDatabaseName(.Properties("Connect").Value)
                End With
            End If
        Next tdf
    End With
End Sub

Einfacher Dateidialog in Python

Manchmal möchte man innerhalb des Python-Skripts einen Dialog anzeigen, um den User z.B. eine Datei auswählen zu lassen. Mit TKinter geht das in Python recht einfach, den Fokus auf den Dialog zu setzen (ihn in den Vordergrund zu holen) ist dabei aber sehr sinnvoll. Folgender Code von Stackexchange (https://stackoverflow.com/questions/3375227/how-to-give-tkinter-file-dialog-focus) tut genau das:

import tkinter as tk
from tkinter import filedialog
 
# Make a top-level instance and hide since it is ugly and big.
root = tk.Tk()
root.withdraw()
 
# Make it almost invisible - no decorations, 0 size, top left corner.
root.overrideredirect(True)
root.geometry('0x0+0+0')
 
# Show window again and lift it to top so it can get focus,
# otherwise dialogs will end up behind the terminal.
root.deiconify()
root.lift()
root.focus_force()
 
filenames = filedialog.askopenfilenames(parent=root) # Or some other dialog
 
# Get rid of the top-level instance once to make it actually invisible.
root.destroy()

Datei vom Sharepoint laden mittels Powershell

Hier ein Code-Schnipsel, zusammenkopiert aus Stackexchange-Antworten, mit dem man eine Datei vom Sharepoint laden kann. Wichtig war hier, dass die eventuell bereits lokal vorhandene Datei nicht mehr genutzt wird. Dazu wird sie gelöscht (man könnte noch prüfen, ob sie überhaupt vorhanden ist…). Der Sharepoint-Pfad wird innerhalb der Powershell als Laufwerk gemountet, das erlaubt dann die Nutzung einfacher Kopier-Befehle.

[String]$Ziel = "somelocalfile.txt"
 
Write-Host "Loesche die alte Datei"
Remove-Item -Path $Ziel
 
$FileExists = Test-Path $Ziel
If ($FileExists -eq $True) {
    Write-Host "Fehler: Datei noch vorhanden!"}
Else {
    Write-Host "OK: Alte Datei geloescht!"
}
 
Write-Host "Mounte Sharepoint als virtuelles Laufwerk..."
[String]$WebDAVShare = '\\some\unc\path\'
New-PSDrive -Name S -PSProvider FileSystem -Root $WebDAVShare
 
Write-Host "Kopiere ..."
Copy-Item "S:/someremotefile.xlsx" $Ziel
 
$FileExists = Test-Path $Ziel
 
If ($FileExists -eq $True) {
    Write-Host "OK: Neue Datei vorhanden!"}
Else {
    Write-Host "Fehler: Datei wurde nicht heruntergeladen!"
}
 
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

Per VBA Arbeitsblätter leeren

Hier ein wenig VBA, um Excel-Blätter zu leeren:

Sub clearthisSheet()
 With Sheets("Tabelle1")
      .Cells.Clear
End With

Das tikz-kalender Paket

Ein kurzer Nachtrag zu meinem „Kalender mit TikZ“-Beispiel. Von Rolf Niepraschk gibt es das „tikz-kalender“ Paket (https://ctan.org/pkg/tikz-kalender), das die notwendige Funktionalität bereitstellt.

Schauen wir uns ein einfaches Beispiel an:

  • als Dokumentenklasse wird tikz-kalender genutzt
  • Als Optionen zum \setup-Befehl gibt man die verschiedenen Variablen in Key-Value Notation an
  • der eigentliche Satz des Kalenders geschieht mittels \makeKalender
  • es wird daraus ein zweiseitiges Dokument mit jeweils einem Halbjahr erzeugt
\documentclass{tikz-kalender}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
 
\setup{year=2018,title={Termine}}
 
\begin{document}
 
\makeKalender
 
\end{document}

Jahreskalender mit LaTeX & TikZ

Hier ein zusammengefrickeltes Beispiel für einen TikZ-basierten Jahreskalender. „Zusammengefrickelt“ deshalb, weil es bestimmt über die TikZ- und pgf-Kalenderfunktionen viel einfacher und eleganter geht. Letzlich tut es aber 😉

Kalender_2018 (auch wenn das PDF im Namen „2017“ trägt)

\documentclass[fontsize=6pt]{scrartcl}
\usepackage[a4paper,landscape,left=0.5cm,right=0.5cm,top=0.5cm,bottom=0.5cm]{geometry}
 
\usepackage[]{ifdraft}
\usepackage[]{attachfile}
\usepackage[]{eso-pic}
 
\usepackage[english]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
 
\renewcommand{\familydefault}{\sfdefault}
\RequirePackage[scaled=0.9]{helvet}
\usepackage{tikz}
\usepackage[right]{showlabels}
\usetikzlibrary{positioning}
\pagestyle{empty}
 
\usepackage{xcolor}
 
\usepackage{hyperref}
\usepackage{url}
 
\definecolor{weekendday}{RGB}{220,220,220}
\newcommand{\file}[1]{\textattachfile{#1}{\textcolor{blue}{\LaTeX\ Sourcecode}}}
 
\begin{document}  
 
\AddToShipoutPictureFG*{
  \put(35,10){\footnotesize Uwe Ziegenhagen, ziegenhagen@gmail.com, \file{\jobname.tex}	
}
}
 
\begin{center}
\begin{tikzpicture}
[
    x=23mm,y=6mm,
    mybox/.style={rectangle,rounded corners,minimum width=23mm, minimum height=6mm},
	month/.style={mybox,align=center,draw=black,fill=yellow,thick,font=\bfseries\Large},
    date/.style={mybox,draw=gray,fill=yellow,align=left,thick,minimum width=5mm,font=\bfseries\Large},
    day/.style={mybox,draw=black,align=left},
    weekendday/.style={mybox,draw=black,align=left,fill=weekendday}
]
\node at (0,0) [month] {Januar};
\node at (1,0) [month] {Februar};
\node at (2,0) [month] {März};
\node at (3,0) [month] {April};
\node at (4,0) [month] {Mai};
\node at (5,0) [month] {Juni};
\node at (6,0) [month] {Juli};
\node at (7,0) [month] {August};
\node at (8,0) [month] {September};
\node at (9,0) [month] {Oktober};
\node at (10,0) [month] {November};
\node at (11,0) [month] {Dezember};
 
\node at (-0.6,-1) [date] {01};
\node at (-0.6,-2) [date] {02};
\node at (-0.6,-3) [date] {03};
\node at (-0.6,-4) [date] {04};
\node at (-0.6,-5) [date] {05};
\node at (-0.6,-6) [date] {06};
\node at (-0.6,-7) [date] {07};
\node at (-0.6,-8) [date] {08};
\node at (-0.6,-9) [date] {09};
\node at (-0.6,-10) [date] {10};
\node at (-0.6,-11) [date] {11};
\node at (-0.6,-12) [date] {12};
\node at (-0.6,-13) [date] {13};
\node at (-0.6,-14) [date] {14};
\node at (-0.6,-15) [date] {15};
\node at (-0.6,-16) [date] {16};
\node at (-0.6,-17) [date] {17};
\node at (-0.6,-18) [date] {18};
\node at (-0.6,-19) [date] {19};
\node at (-0.6,-20) [date] {20};
\node at (-0.6,-21) [date] {21};
\node at (-0.6,-22) [date] {22};
\node at (-0.6,-23) [date] {23};
\node at (-0.6,-24) [date] {24};
\node at (-0.6,-25) [date] {25};
\node at (-0.6,-26) [date] {26};
\node at (-0.6,-27) [date] {27};
\node at (-0.6,-28) [date] {28};
\node at (-0.6,-29) [date] {29};
\node at (-0.6,-30) [date] {30};
\node at (-0.6,-31) [date] {31};
 
\node at (0,-1) [day] {};
\node at (0,-2) [day] {};
\node at (0,-3) [day] {};
\node at (0,-4) [day] {};
\node at (0,-5) [day] {};
\node at (0,-6) [weekendday] {};
\node at (0,-7) [weekendday] {};
\node at (0,-8) [day] {};
\node at (0,-9) [day] {};
\node at (0,-10) [day] {};
\node at (0,-11) [day] {};
\node at (0,-12) [day] {};
\node at (0,-13) [weekendday] {};
\node at (0,-14) [weekendday] {};
\node at (0,-15) [day] {};
\node at (0,-16) [day] {};
\node at (0,-17) [day] {};
\node at (0,-18) [day] {};
\node at (0,-19) [day] {};
\node at (0,-20) [weekendday] {};
\node at (0,-21) [weekendday] {};
\node at (0,-22) [day] {};
\node at (0,-23) [day] {};
\node at (0,-24) [day] {};
\node at (0,-25) [day] {};
\node at (0,-26) [day] {};
\node at (0,-27) [weekendday] {};
\node at (0,-28) [weekendday] {};
\node at (0,-29) [day] {};
\node at (0,-30) [day] {};
\node at (0,-31) [day] {};
 
 
\node at (1,-1) [day] {};
\node at (1,-2) [day] {};
\node at (1,-3) [weekendday] {};
\node at (1,-4) [weekendday] {};
\node at (1,-5) [day] {};
\node at (1,-6) [day] {};
\node at (1,-7) [day] {};
\node at (1,-8) [day] {};
\node at (1,-9) [day] {};
\node at (1,-10) [weekendday] {};
\node at (1,-11) [weekendday] {};
\node at (1,-12) [day] {};
\node at (1,-13) [day] {};
\node at (1,-14) [day] {};
\node at (1,-15) [day] {};
\node at (1,-16) [day] {};
\node at (1,-17) [weekendday] {};
\node at (1,-18) [weekendday] {};
\node at (1,-19) [day] {};
\node at (1,-20) [day] {};
\node at (1,-21) [day] {};
\node at (1,-22) [day] {};
\node at (1,-23) [day] {};
\node at (1,-24) [weekendday] {};
\node at (1,-25) [weekendday] {};
\node at (1,-26) [day] {};
\node at (1,-27) [day] {};
\node at (1,-28) [day] {};
 
 
 
\node at (2,-1) [day] {};
\node at (2,-2) [day] {};
\node at (2,-3) [weekendday] {};
\node at (2,-4) [weekendday] {};
\node at (2,-5) [day] {};
\node at (2,-6) [day] {};
\node at (2,-7) [day] {};
\node at (2,-8) [day] {};
\node at (2,-9) [day] {};
\node at (2,-10) [weekendday] {};
\node at (2,-11) [weekendday] {};
\node at (2,-12) [day] {};
\node at (2,-13) [day] {};
\node at (2,-14) [day] {};
\node at (2,-15) [day] {};
\node at (2,-16) [day] {};
\node at (2,-17) [weekendday] {};
\node at (2,-18) [weekendday] {};
\node at (2,-19) [day] {};
\node at (2,-20) [day] {};
\node at (2,-21) [day] {};
\node at (2,-22) [day] {};
\node at (2,-23) [day] {};
\node at (2,-24) [weekendday] {};
\node at (2,-25) [weekendday] {};
\node at (2,-26) [day] {};
\node at (2,-27) [day] {};
\node at (2,-28) [day] {};
\node at (2,-29) [day] {};
\node at (2,-30) [day] {};
\node at (2,-31) [weekendday] {};
 
\node at (3,-1) [weekendday] {};
\node at (3,-2) [day] {};
\node at (3,-3) [day] {};
\node at (3,-4) [day] {};
\node at (3,-5) [day] {};
\node at (3,-6) [day] {};
\node at (3,-7) [weekendday] {};
\node at (3,-8) [weekendday] {};
\node at (3,-9) [day] {};
\node at (3,-10) [day] {};
\node at (3,-11) [day] {};
\node at (3,-12) [day] {};
\node at (3,-13) [day] {};
\node at (3,-14) [weekendday] {};
\node at (3,-15) [weekendday] {};
\node at (3,-16) [day] {};
\node at (3,-17) [day] {};
\node at (3,-18) [day] {};
\node at (3,-19) [day] {};
\node at (3,-20) [day] {};
\node at (3,-21) [weekendday] {};
\node at (3,-22) [weekendday] {};
\node at (3,-23) [day] {};
\node at (3,-24) [day] {};
\node at (3,-25) [day] {};
\node at (3,-26) [day] {};
\node at (3,-27) [day] {};
\node at (3,-28) [weekendday] {};
\node at (3,-29) [weekendday] {};
\node at (3,-30) [day] {};
 
\node at (4,-1) [day] {};
\node at (4,-2) [day] {};
\node at (4,-3) [day] {};
\node at (4,-4) [day] {};
\node at (4,-5) [weekendday] {};
\node at (4,-6) [weekendday] {};
\node at (4,-7) [day] {};
\node at (4,-8) [day] {};
\node at (4,-9) [day] {};
\node at (4,-10) [day] {};
\node at (4,-11) [day] {};
\node at (4,-12) [weekendday] {};
\node at (4,-13) [weekendday] {};
\node at (4,-14) [day] {};
\node at (4,-15) [day] {};
\node at (4,-16) [day] {};
\node at (4,-17) [day] {};
\node at (4,-18) [day] {};
\node at (4,-19) [weekendday] {};
\node at (4,-20) [weekendday] {};
\node at (4,-21) [day] {};
\node at (4,-22) [day] {};
\node at (4,-23) [day] {};
\node at (4,-24) [day] {};
\node at (4,-25) [day] {};
\node at (4,-26) [weekendday] {};
\node at (4,-27) [weekendday] {};
\node at (4,-28) [day] {};
\node at (4,-29) [day] {};
\node at (4,-30) [day] {};
\node at (4,-31) [day] {};
 
\node at (5,-1) [day] {};
\node at (5,-2) [weekendday] {};
\node at (5,-3) [weekendday] {};
\node at (5,-4) [day] {};
\node at (5,-5) [day] {};
\node at (5,-6) [day] {};
\node at (5,-7) [day] {};
\node at (5,-8) [day] {};
\node at (5,-9) [weekendday] {};
\node at (5,-10) [weekendday] {};
\node at (5,-11) [day] {};
\node at (5,-12) [day] {};
\node at (5,-13) [day] {};
\node at (5,-14) [day] {};
\node at (5,-15) [day] {};
\node at (5,-16) [weekendday] {};
\node at (5,-17) [weekendday] {};
\node at (5,-18) [day] {};
\node at (5,-19) [day] {};
\node at (5,-20) [day] {};
\node at (5,-21) [day] {};
\node at (5,-22) [day] {};
\node at (5,-23) [weekendday] {};
\node at (5,-24) [weekendday] {};
\node at (5,-25) [day] {};
\node at (5,-26) [day] {};
\node at (5,-27) [day] {};
\node at (5,-28) [day] {};
\node at (5,-29) [day] {};
\node at (5,-30) [weekendday] {};
 
 
\node at (6,-1) [weekendday] {};
\node at (6,-2) [day] {};
\node at (6,-3) [day] {};
\node at (6,-4) [day] {};
\node at (6,-5) [day] {};
\node at (6,-6) [day] {};
\node at (6,-7) [weekendday] {};
\node at (6,-8) [weekendday] {};
\node at (6,-9) [day] {};
\node at (6,-10) [day] {};
\node at (6,-11) [day] {};
\node at (6,-12) [day] {};
\node at (6,-13) [day] {};
\node at (6,-14) [weekendday] {};
\node at (6,-15) [weekendday] {};
\node at (6,-16) [day] {};
\node at (6,-17) [day] {};
\node at (6,-18) [day] {};
\node at (6,-19) [day] {};
\node at (6,-20) [day] {};
\node at (6,-21) [weekendday] {};
\node at (6,-22) [weekendday] {};
\node at (6,-23) [day] {};
\node at (6,-24) [day] {};
\node at (6,-25) [day] {};
\node at (6,-26) [day] {};
\node at (6,-27) [day] {};
\node at (6,-28) [weekendday] {};
\node at (6,-29) [weekendday] {};
\node at (6,-30) [day] {};
\node at (6,-31) [day] {};
 
\node at (7,-1) [day] {};
\node at (7,-2) [day] {};
\node at (7,-3) [day] {};
\node at (7,-4) [weekendday] {};
\node at (7,-5) [weekendday] {};
\node at (7,-6) [day] {};
\node at (7,-7) [day] {};
\node at (7,-8) [day] {};
\node at (7,-9) [day] {};
\node at (7,-10) [day] {};
\node at (7,-11) [weekendday] {};
\node at (7,-12) [weekendday] {};
\node at (7,-13) [day] {};
\node at (7,-14) [day] {};
\node at (7,-15) [day] {};
\node at (7,-16) [day] {};
\node at (7,-17) [day] {};
\node at (7,-18) [weekendday] {};
\node at (7,-19) [weekendday] {};
\node at (7,-20) [day] {};
\node at (7,-21) [day] {};
\node at (7,-22) [day] {};
\node at (7,-23) [day] {};
\node at (7,-24) [day] {};
\node at (7,-25) [weekendday] {};
\node at (7,-26) [weekendday] {};
\node at (7,-27) [day] {};
\node at (7,-28) [day] {};
\node at (7,-29) [day] {};
\node at (7,-30) [day] {};
 
 
\node at (8,-1) [day] {};
\node at (8,-2) [weekendday] {};
\node at (8,-3) [weekendday] {};
\node at (8,-4) [day] {};
\node at (8,-5) [day] {};
\node at (8,-6) [day] {};
\node at (8,-7) [day] {};
\node at (8,-8) [day] {};
\node at (8,-9) [weekendday] {};
\node at (8,-10) [weekendday] {};
\node at (8,-11) [day] {};
\node at (8,-12) [day] {};
\node at (8,-13) [day] {};
\node at (8,-14) [day] {};
\node at (8,-15) [day] {};
\node at (8,-16) [weekendday] {};
\node at (8,-17) [weekendday] {};
\node at (8,-18) [day] {};
\node at (8,-19) [day] {};
\node at (8,-20) [day] {};
\node at (8,-21) [day] {};
\node at (8,-22) [day] {};
\node at (8,-23) [weekendday] {};
\node at (8,-24) [weekendday] {};
\node at (8,-25) [day] {};
\node at (8,-26) [day] {};
\node at (8,-27) [day] {};
\node at (8,-28) [day] {};
\node at (8,-29) [day] {};
\node at (8,-30) [weekendday] {};
\node at (8,-31) [weekendday] {};
 
 
\node at (9,-1) [day] {};
\node at (9,-2) [day] {};
\node at (9,-3) [day] {};
\node at (9,-4) [day] {};
\node at (9,-5) [day] {};
\node at (9,-6) [weekendday] {};
\node at (9,-7) [weekendday] {};
\node at (9,-8) [day] {};
\node at (9,-9) [day] {};
\node at (9,-10) [day] {};
\node at (9,-11) [day] {};
\node at (9,-12) [day] {};
\node at (9,-13) [weekendday] {};
\node at (9,-14) [weekendday] {};
\node at (9,-15) [day] {};
\node at (9,-16) [day] {};
\node at (9,-17) [day] {};
\node at (9,-18) [day] {};
\node at (9,-19) [day] {};
\node at (9,-20) [weekendday] {};
\node at (9,-21) [weekendday] {};
\node at (9,-22) [day] {};
\node at (9,-23) [day] {};
\node at (9,-24) [day] {};
\node at (9,-25) [day] {};
\node at (9,-26) [day] {};
\node at (9,-27) [weekendday] {};
\node at (9,-28) [weekendday] {};
\node at (9,-29) [day] {};
\node at (9,-30) [day] {};
\node at (9,-31) [day] {};
 
\node at (10,-1) [day] {};
\node at (10,-2) [day] {};
\node at (10,-3) [weekendday] {};
\node at (10,-4) [weekendday] {};
\node at (10,-5) [day] {};
\node at (10,-6) [day] {};
\node at (10,-7) [day] {};
\node at (10,-8) [day] {};
\node at (10,-9) [day] {};
\node at (10,-10) [weekendday] {};
\node at (10,-11) [weekendday] {};
\node at (10,-12) [day] {};
\node at (10,-13) [day] {};
\node at (10,-14) [day] {};
\node at (10,-15) [day] {};
\node at (10,-16) [day] {};
\node at (10,-17) [weekendday] {};
\node at (10,-18) [weekendday] {};
\node at (10,-19) [day] {};
\node at (10,-20) [day] {};
\node at (10,-21) [day] {};
\node at (10,-22) [day] {};
\node at (10,-23) [day] {};
\node at (10,-24) [weekendday] {};
\node at (10,-25) [weekendday] {};
\node at (10,-26) [day] {};
\node at (10,-27) [day] {};
\node at (10,-28) [day] {};
\node at (10,-29) [day] {};
\node at (10,-30) [day] {};
 
 
\node at (11,-1) [weekendday] {};
\node at (11,-2) [weekendday] {};
\node at (11,-3) [day] {};
\node at (11,-4) [day] {};
\node at (11,-5) [day] {};
\node at (11,-6) [day] {};
\node at (11,-7) [day] {};
\node at (11,-8) [weekendday] {};
\node at (11,-9) [weekendday] {};
\node at (11,-10) [day] {};
\node at (11,-11) [day] {};
\node at (11,-12) [day] {};
\node at (11,-13) [day] {};
\node at (11,-14) [day] {};
\node at (11,-15) [weekendday] {};
\node at (11,-16) [weekendday] {};
\node at (11,-17) [day] {};
\node at (11,-18) [day] {};
\node at (11,-19) [day] {};
\node at (11,-20) [day] {};
\node at (11,-21) [day] {};
\node at (11,-22) [weekendday] {};
\node at (11,-23) [weekendday] {};
\node at (11,-24) [day] {};
\node at (11,-25) [day] {};
\node at (11,-26) [day] {};
\node at (11,-27) [day] {};
\node at (11,-28) [day] {};
\node at (11,-29) [weekendday] {};
\node at (11,-30) [weekendday] {};
\node at (11,-31) [day] {};
 
\end{tikzpicture}
\end{center}
 
\end{document}