17. April 2016, Kategorie:

Wort-Uhr (Teil 3, Software und Sommerzeit)

Es folgt der letzte Teil dieser Artikelserie. Hier geht es um die Software, die auf dem Particle.io Photon läuft und speziell um die Probleme mit der Sommerzeit und Zeitzonen. Zuletzt gehe ich noch auf ein paar Ideen ein, die man in die Software integrieren könnten.

Hier in der Schweiz gilt die Zeitzone UTC+1. Wie ihr wisst kommt zusätzlich zu dieser Stunde während dem Sommerhalbjahr nochmals eine Stunde dazu. Wir haben also zwei verschiedene Zeitzonen.

Vom letzten Sonntag im März 02:00 bis zum letzten Sonntag im Oktober 03:00 leben wir in UTC+2 und die restliche Zeit in UTC+1. Selbstverständlich baue ich keine Uhr, die manuell gestellt werden muss. Ausserdem hat die Firwmare des Photon bereits eine eingebaute Zeitsynchronisation. Wie fast alle Uhrzeiten in der IT synchronisiert der aber auf UTC. Ausserdem kennt die Firmware vom Photon keine Sommer- bzw Winterzeit.

Wie findet man nun auf einem kleinen Mikrocontroller heraus, ob wir zur UTC-Zeit eine oder zwei Stunden hinzufügen müssen (Winter-/Sommerzeit)? Ganz einfach, man bescheisst… :). Es ist alles andere als trivial den letzten Sonntag im März/Oktober zu identifizieren also habe ich mal kurz die entsprechenden Tage für die nächsten 24 Jahre rausgesucht und eingebaut:

static const uint16_t _baseYear = 2016;
static const uint16_t _maxYear  = 2040;
//                                  2016 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
static const uint8_t _EuDSTStart[] = {27,26,25,31,29,28,27,26,31,30,29,28,26,25,31,30,28,27,26,25,30,29,28,27,25};
static const uint8_t _EuDSTEnd[]   = {30,29,28,27,25,31,30,29,27,26,25,31,29,28,27,26,31,30,29,28,26,25,31,30,25};

Jetzt fehlt nur noch eine Funktion, die für eine bestimmte Uhrzeit erkennen kann, ob die in den Bereich fällt, während die Sommerzeit gilt.

bool isEuroDST(uint32_t tnow) {
  // 1am last Sunday in March to 1am on last Sunday October (UTC!)
  uint32_t day = Time.day(tnow);
  uint32_t year = Time.year(tnow);
  uint8_t  month = Time.month(tnow);

  // Always return false if no data is available for this year
  if (year > _maxYear || year < _baseYear) {
    return false;
  }
  if (month>3 && month<10) {
    return true;
  } else if (month == 3) {
    if ((day == _EuDSTStart[year-_baseYear] && Time.hour(tnow) >= 1) ||
	      (day >  _EuDSTStart[year-_baseYear])) {
      return true;
    }
  } else if (month == 10) {
    if (!((day == _EuDSTEnd[year-_baseYear] && Time.hour(tnow) >= 1) ||
	        (day >  _EuDSTEnd[year-_baseYear]))) {
      return true;
    }
  }
  return false;
}

Im oberen Bereich werden die Funktionen der Firmware genutzt um den übergebenen Zeitstempel in Tag, Monat und Jahr aufzubrechen. Danach wird, geprüft ob das Datum im Bereich der Sommerzeit liegt oder nicht und dazu die oben erwähnte Tabelle genutzt. Die Monate April bis September sind immer Sommerzeit und werden im ersten Teil abgehandelt. Für die Monate März (3) und Oktober (10) wird die Tabelle und Uhrzeit genutzt um es exakt festzustellen. November bis Februar sind immer Winterzeit und werden mit dem „return false“ auf der letzten Zeile abgehandelt.

Wir wissen nun also die aktuelle Uhrzeit. Aber sehen tut man noch nichts auf dem Display. Dazu ist es nötig, abhängig von der Uhrzeit, gewisse LEDs ein- bzw. auszuschalten. Das wird komplizierter wegen dieser zick-zack Verdrahtung der LEDs. Schlussendlich habe ich mir im Programm ein Array von Listen angelegt, die für jede Zeit angeben, welche LEDs jeweils eingeschaltet werden müssen. Als letzter Eintrag in diesen Listen habe ich immer -1 erfasst, da ich ja irgendwie erkennen muss, wenn die Liste fertig ist. In der Programmiersprache C gibt es keinen Befehl um die Länge der Liste abzufragen.

int8_t mins5[][13] = {
  {-1}, // 0min
  {74, 93, 94, 113 /*FÜNF*/, 77, 90, 97, 110 /*NACH*/, -1}, //  5min
  {12, 15, 32, 35 /*ZEHN*/, 77, 90, 97, 110 /*NACH*/, -1}, // 10min
  {51, 56, 71, 76, 91, 96, 111 /*VIERTEL*/, 77, 90, 97, 110 /*NACH*/, -1}, // 15min
  {52, 55, 72, 75, 92, 95, 112 /*ZWANZIG*/, 77, 90, 97, 110 /*NACH*/, -1}, // 20min
  {74, 93, 94, 113 /*FÜNF*/, 10, 17, 30 /*VOR*/, 9, 18, 29, 38 /*HALB*/, -1}, // 25min
  {9, 18, 29, 38 /*HALB*/, -1}, // 30min
  {74, 93, 94, 113 /*FÜNF*/, 77, 90, 97, 110 /*NACH*/, 9, 18, 29, 38 /*HALB*/, -1}, // 35min
  {52, 55, 72, 75, 92, 95, 112 /*ZWANZIG*/, 10, 17, 30 /*VOR*/, -1}, // 40min
  {51, 56, 71, 76, 91, 96, 111 /* VIERTEL */, 10, 17, 30 /*VOR*/, -1}, // 45min
  {12, 15, 32, 35 /*ZEHN*/, 10, 17, 30 /*VOR*/, -1}, // 50min
  {74, 93, 94, 113 /*FÜNF*/, 10, 17, 30 /*VOR*/, -1}, // 55min
};

Also nehme ich die aktuelle „Minute“, teile die durch 5 und weiss schon, welche der obigen Listen ich einschalten muss. Das funktioniert aber nur, weil in C eine Division von Ganzzahlen (Integer) immer abrundet. Die Darstellung der Stunden ist sogar noch einfacher, da ich die Stunden direkt in der Liste nachschlagen kann ohne erst noch etwas berechnen zu müssen.

Wie weiter?

Was soll ich sagen… die Uhr funktioniert super! Inzwischen ist das bei mir Zuhause die am häufigsten genutzte Uhr, wenn ich die Zeit wissen will. Die Helligkeit der LEDs muss ich noch optimieren und vermutlich werde ich die gefräste Maske noch weiss anmalen um das Licht besser zu reflektieren. Ich hoffe damit die Lesbarkeit von der Seite zu verbessern.

Für die Software habe ich noch viele Ideen. Die ganze Uhr kann als 11×10 RGB LED-Matrix genutzt werden. Man könnte also grosse Buchstaben darüberscrollen lassen. Oder Animationen einbauen. Die Uhr könnte als Kommunikationsplattform für alles mögliche genutzt werden. Zum Beispiel als Erinnerung, dass die Pflanzen gerne mal wieder Wasser hätten oder, dass die Waschmaschine mit dem Programm durch ist. Durch den eingesetzen Photon Mikrocontroller ist die Uhr bereits „Cloud-Ready“ und kann problemlos Events empfangen, die von einem PC oder einem anderen Mikrocontroller geschickt werden.

Ich will auch eine!

Das Löten der LEDs und auch das Aufkleben der Folie sind eine unglaubliche Fummelarbeit und brauchen viel Zeit. Auch sind diese Art von Uhren vermutlich urheberrechtlich geschützt und daher wird es keinen Workshop zum Erstellen dieser Uhren geben und ich werde vermutlich auch keine weiteren Exemplare mehr herstellen.

Die Grafiken (Affinity Designer für 2D, Google SketchUp für 3D) gebe ich gerne weiter. Die komplette Software ist auf unserem GitLab verfügbar und darf selbstverständlich auch benutzt werden. Einfach bei mir melden, falls jemand so ein Projekt starten möchte.

Was könnte man mit der Uhr noch machen? Was habt ihr bereits für Uhren gebaut? Schickt Fotos!!!

3 Kommentare

  • Sibylle

    Ich würde sehr gerne zusammen mit anderen so eine Uhr bauen. Gerne mit arduino. Alleine trau ich mich da nicht ran.
    Wäre toll. Dann könnte man auch das Material zusammen besorgen. Seht ihr da eine Möglichkeit?


    • Hoi Sibylle

      Die Materialbeschaffung war ziemlich „ereignislos“. Rahmen aus der IKEA, Moosgummi und Holz aus coop Bau&Hobby. Die Vinylfolie habe ich bei Brack beschafft und der Mikrocontroller kommt vom Pi-Shop.ch. Dieser Photon hat gegenüber dem Arduino den Vorteil, dass WLAN integriert ist und somit einfach die aktuelle Uhrzeit aus dem Internet bekannt ist. Beim Arduino ist das aufwändiger. Elektronik und Material ist der kleinere Teil bei diesem Projekt und einfach reproduzierbar mit der Basis von mir. Hauptsächlich ist es eine Fleissarbeit und manchmal auch ein ziemliches Gefummel. Aber es lohnt sich meiner Meinung nach. Ich bin sehr zufrieden mit dem Resultat.

      Am 11. und 25. Juni bin ich im Makerspace und kann gerne die Uhr mitbringen und vielleicht noch den einen oder anderen Tipp geben. Melde dich doch bitte vorher bei thomas(at)makerspace-rheinfelden.ch. Nicht, dass ich dann doch noch die Uhr vergessen sollte…


      • Sibylle

        Lieber Thomas
        Merci für die Info. Ich schaue, dass ich am 25.6. vorbeikommen kann und mir dein Werk mal genauer anschauen kann. Liebe Grüsse Sibylle


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert