toit

toit Grundlagen

IoT Plattform und Programmiersprache

toit ist eine IoT Plattform und eine Open Source Programmiersprache. Das ist auf den ersten Blick etwas verwirrend, da man beide Projekte im Kopf trennen muss obwohl sie vom selben Team erschaffen wurden.

In dieser Sendung schauen wir uns beide Projekte an, installieren toit und jag und lernen die Grundlagen der Programmiersprache. In den nächsten Wochen werden wir uns dann die IoT Plattform in Detail angucken und auch andere IoT Plattformen mit MQTT und HTTP verwenden.

toit IoT Plattform

Bei der toit IoT Plattform handelt es sich um eine kommerzielle Plattform, mit der man IoT Geräte verwalten und Daten verarbeiten kann. Es ist sogar möglich, neue Firmware direkt im Webbrowser zu schreiben und auf ausgewählte Geräte über das Internet zu verteilen.

https://docs.toit.io/getstarted/installation

Wir schauen uns diese Woche nur kurz an, wie man ein neues Gerät mit der Web Plattform in Betrieb nimmt. Die Details der Plattform sehen wir uns in einer zukünftigen Folge an. Dann wird es auch um PubSub gehen und die REST API, womit man die Daten in eigenen Anwendungen nutzen kann.

Diese Woche wollen wir uns auf die Programmiersprache und die Nutzung ohne Cloud konzentrieren.

toit Open Source Programmiersprache

Aktuell kann man die toit Programmiersprache nur mit einem ESP32 verwenden und sie ist für diesen Mikrocontroller und das Internet der Dinge optimiert.

Das besondere an toit ist, dass jedes Programm in einem Container - also einem Sandkasten - läuft und somit vom Kernel und von anderen Programmen isoliert ist. Wenn ein Programm abstürzt, bleibt nicht das gesamte System hängen.

Die moderne Programmiersprache kennt Objekte und Klassen und hat einen optimierten Garbagecollector für embedded systems. Neben command-line-interface (CLI) Werkzeugen gibt es auch eine Extension für Visucal Studio Code.

Der Quellcode befindet sich in diesem github Repository: https://github.com/toitlang/toit

Es ist wichtig zu verstehen, dass die Versionen der open source Programmiersprache sich unterscheiden von den Versionen, die man über toit.io installiert. Die Version von toit.io beinhaltet zusätzliche Bibliotheken, um mit der Plattform zu kommunizieren und dafür fehlen andere Elemente. Aktuell nutzt die toit.io Version die Release 1.6.9 und die toitlang Version aus github die Release 1.6.10 - Die Version 1.6.9 ist allerdings nicht in github zu finden, da sie scheinbar eine unterschiedliche Codebase verwendet. Die kommerzielle Version von toit.io verwendet folgende Standardbibliothek: https://libs.toit.io/

Der Syntax von toit ähnelt Python. Es wird kein Semikolon verwendet und anstelle von geschweiften Klammern rückt man seinen Quellcode ein.

Jaguar

Bevor wir uns die Programmiersprache genauer angucken, müssen wir das jag Tool installieren, das unsere Programme kompiliert und auf den Mikrocontroller flasht. Alle Details inkl. Installationsanleitung findet man hier (und in unserem Video): https://github.com/toitlang/jaguar

Funktionsdefinitionen

Funktionen haben mindestens einen Funktionsnamen, auf den ein Doppelpunkt folgt. In den darauf folgenden, eingerückten Zeilen steht der Funktionskörper. Wenn eine Funktion Parameter verwendet, stehen diese vor dem Doppelpunkt. Um eine Funktion mit Parametern aufzurufen, benutzt man keine runden Klammern, sondern trent die Parameter nur durch Leerzeichen vom Funktionsnamen.

hi:
  print "Hello World!"

hello name:
  print "Hello $name!"

main: 
  hi
  hello "World"

Variablen und Konditionen

toit kennt Variablen, die mit dem Operator := definiert werden. Konstanten werden mit dem Operator ::= definiert.

Wie jede objektorientierte Programmiersprache kennt auch toit if-Statements.

main:
  c ::= 1
  x := 0
  if x != c:
    x = 42
  
  y := ?
  if (random 2) == 0:
    y = 1
  else:
    y = 42

Typen

Auch primitive Typen wie int sind Klassen in toit. Sie haben also auch Methoden, wie das folgende Beispiel zeigt.

//gibt den absoluten Wert von x zurück
foo x/int -> int:
  return x.abs

Sogar Zahlen können als Objekte betrachtet werden und sie haben z.B. die Funktion repeat.

main:
  10.repeat:
    print "."

Steht hinter einer Variablen oder eine Funktionsdefinition ein Slash (/), so kann der Typ der Variablen definiert werden. Der Rückgabewert einer Funktion steht nach dem -> Operator.

Blöcke

Blöcke werden sehr häufig in toit verwendet. Es sind Callbacks zu Funktionen. Hier zwei wichtige Beispiele:

main:
  // Gibt die Zahlen 1 bis 10 aus, eine pro Zeile.
  10.repeat:
    print it + 1

  // Gibt die Elemente der Liste aus, eins pro Zeile.
  ["digitale", "dinge", "dienstags", "21 Uhr"].do:
    print it

Das Blockelement "it" wird als Variable genutzt, das den aktuellen Wert des zu iterierenden Elements beinhaltet. Man kann das Blockelement aber auch benennen oder mehrere verwenden, wie das folgende Beispiel zeigt:

main:
  map ::= {
    1234: "Peter",
    5678: "Paul",
    9: "Maria"
    }
  map.do | id name |
    print "$name hat die ID $id"

Mehr über Blöcke erfahrt ihr hier: https://docs.toit.io/language/blocks

GPIO

Das Paket gpio ist immer installiert, muss jedoch in einem Programm importiert werden, damit es genutzt werden kann.

Dieses Programm lässt eine LED an Port 22 zehn mal blinken:

import gpio

pin := gpio.Pin 22

blink:
  pin.set 1
  sleep --ms=1000
  pin.set 0
  sleep --ms=1000

main:
  pin.config --output 
  10.repeat:
    blink
  
  //Pin für andere Anwendungen freigeben
  pin.close

digitale Eingabe: Button

Wir fügen einen Button an Pin 34 hinzu und aktivieren den Pull-Up Widerstand des Pins:

import gpio

led := gpio.Pin 22 --output
button := gpio.Pin 34 --input --pull_up

blink:
  led.set 1
  sleep --ms=100
  led.set 0
  sleep --ms=100

main:
  while true:
    button.wait_for 0
    3.repeat:
      blink
  led.close
  button.close

ADC

In toit können auch die analogen Eingänge des ESP32 abgefragt werden. Allerdings unterstützt toit nur den ADC1, also nur Pin32-39. ADC2 wird nicht unterstützt! Die get Methode gibt einen Float Wert zurück, der die Spannung in Volt repräsentiert. Dieses einfache Beispiel liest den Wert von Pin 39 aus und gibt ihn aus:

import gpio
import gpio.adc show Adc

main:
  adc := Adc (gpio.Pin 39)
  print adc.get
  adc.close

Pulsweitenmodulation - PWM

Um quasi analoge Spannungen an einem GPIO Pin auszugeben, nutzt der Arduino die Funktion analogWrite(). Unter der Haube nutzt der klassische Arduino dafür PWM. In toit können wir PWM direkt nutzen. Dieses Beispiel faded eine LED an Pin 22:

import gpio
import gpio.pwm

main:
  led := gpio.Pin 22
  generator := pwm.Pwm --frequency=400
  channel := generator.start led
  duty_percent := 0
  step := 1
  while true:
    channel.set_duty_factor duty_percent/100.0
    duty_percent += step
    if duty_percent == 0 or duty_percent == 100:
      step = -step
    sleep --ms=10
  led.close

Klassen und Objekte

class Point: 
  x := 42
  y/int := 103
  static ZERO/int ::= 0

main:
  //erzeugt eine neue Instanz der Klasse Point
  p := Point
  //gibt den Wert der Klassenvariablen x (42) aus. 
  print p.x
  //gibt den Wert der Klassenvariablen y (103) aus. 
  print p.y

Private Klassenvariablen nutzen einen Underscore "_" am Ende des Variablennamens. Es bietet sich an, in diesem Fall auf Getter und Setter zurückzugreifen, wie man sie auch aus anderen objektorientierten Programmiersprachen kennt:

class Point:
  x_ /int := ? // Privates Feld.
  y/int := 0 //public Field.

  constructor .x_:

  // Getter, returnt ein int.
  x -> int:
    return x_

  // Setter, nimmt ein int, returnt nichts.
  x= value/int -> none:
    x_ = value
    print "x_ hat nun den Wert $x_"

Vererbung

Eine Klasse kann mit dem Schlüsselwort extends erweitert werden.

class Point:
  x /int := 0
  y /int := 0

class Point3D extends Point:
  z /int := 0

main:
  p = Point3D
  p.x = 42   
  p.y = 13
  p.z = 103  

Natürlich gibt es auch Interfaces und Super-Konstruktoren und vieles mehr. Details stehen in der toit Language Dokumentation in diesem Kapitel: https://docs.toit.io/language/objects-constructors-inheritance-interfaces

Der Paketmanager

Es gibt mindestens zwei Registries, die toit Pakete anbieten und man kann dem Paketmanager auch direkt eine URL (z.B. zu einem github Repository) übergeben.

Wenn man die toit CLI verwendet (von der toit IoT Plattform), kann man ein Paket wie folgt installieren:

toit pkg install github.com/toitware/toit-morse

Wer hingegen Jaguar, also das jag cli Tool verwendet, ruft diesen Befehl auf:

jag pkg install github.com/toitware/toit-morse

Der Befehlsumfang von toit pkg und jag pkg scheint identisch zu sein, könnte sich aber im Laufe der Zeit verändern. Aktuell verwenden beide Tools die selbe Registry, welche man mit diesem Befehl ermitteln kann:

toit pkg registry list

oder mit Jaguar:

jag pkg registry list

Es gibt auch ein Webinterface für die Registry, was die Suche nach passenden Paketen sehr vereinfacht: https://pkg.toit.io/

Wir sind jeden Dienstag um 21 Uhr live uns sprechen über digitale Dinge! Über einen Kommentar unter dem Video freuen wir uns sehr und noch schöner ist es, wenn wir uns im Live-Chat auf YouTube und Discord austauschen können. Du findest uns bei http://discord.digitale-dinge.de/

Links zur Sendung

Die Open-Source Programmiersprache und ihre Tools:

Die kommerzielle IoT Programmiersprache und ihre Tools: