AdSense

Freitag, 31. Oktober 2014

Arduino Nano V3.0 Klon mit CH340G in Betrieb nehmen

Bei Ebay gibt es einen Klon des Arduino Nano schon für unter 3 Euro zu kaufen. Meist unter dem Namen "Nano V3.0 ATmega328 CH340G" mit dem Zusatz "for Arduino" oder "Arduino compatible", wie zum Beispiel hier. Bei diesen Klonen kommt als USB-Seriell-Wandler nicht wie beim Original ein FT232R sondern (wie der Name schon erkennen lässt) ein CH340G zum Einsatz. Daher sind auch die Treiber der Arduino IDE ungeeignet, stattdessen muss ein extra Treiber von Hand installiert werden. Dieser kann hier beim Hersteller herunter geladen werden. Sollte der Link direkte nicht mehr funktionieren, einfach nach "ch341ser.zip" suchen. Es sind auch Treiber für MAC oder Linux erhältlich. Ich werde hier nur auf die Installation unter Windows eingehen. Zuerst muss das ZIP-Archiv entpackt werden. Falls die Version für 64bit-Windows benötigt wird, muss dann die Datei "DRVSETUP64.exe" aus dem Ordner "DRVSETUP64" in den darüberliegenden Ordner (der unter anderem die Datei "CH341SER.INF" enthält) kopiert werden. Je nach System muss dann die "SETUP.EXE" (32bit) oder die "DRVSETUP64.exe" (64bit) ausgeführt werden. Dann wird auf "INSTALL" geklickt und der Treiber damit installiert.  Damit die Installation des Treibers reibungslos abläuft, darf das Board dabei NICHT eingesteckt sein. Erst NACH der Installation wird der Arduino Nano eingestöpselt. Er sollte dann von Windows erkannt werden.

Sonntag, 5. Oktober 2014

C# - Programm zum Lösen von Sudokus

(English version) Ein Sudoku von Hand lösen ist nicht weiter schwer, irgendwann überkommt einen Programmierer aber dann die Lust, ein Programm zu schreiben, was Sudokus selber löst. Die Grundidee ist einfach. Das erste freie Kästchen wird ausgefüllt (mit einer 1). Dann wird geprüft ob das Sudoku noch korrekt ist. Falls ja, wird das nächste Kästchen ausgefüllt, falls nicht wird das vorige Kästchen eins hochgezählt. Das wird wiederholt, bis das Sudoku komplett ausgefüllt ist.

Zuallererst habe ich ein Fenster erstellt, welches das Sudoku anzeigt:

<Window x:Class="SudokuSolver.SudokuShowWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SudokuShowWindow" Height="550" Width="550">
    <Grid Name="Grid1" HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
        </Grid.RowDefinitions>

    </Grid>
</Window>

Und der dazugehörige Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace SudokuSolver
{
    /// <summary>
   /// Interaktionslogik für SudokuShowWindow.xaml
    /// </summary>
    public partial class SudokuShowWindow : Window
    {
        public SudokuShowWindow()
        {
            InitializeComponent();
        }

        public int[] numbers;
        public TextBlock[] TextBlocks;

        public void refreshValues(int[] _numbers)
        {
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (_numbers[i * 9 + j] != numbers[i * 9 + j])
                    {

                        TextBlocks[i * 9 + j].Text = _numbers[i * 9 + j].ToString();
                    }
                }
            }
        }

        public static SudokuShowWindow newSudokuShowWindow(int[] numbers)
        {
            SudokuShowWindow window = new SudokuShowWindow();
            window.numbers = new int[81];
            window.TextBlocks = new TextBlock[81];
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    window.numbers[i * 9 + j] = numbers[i * 9 + j];
                    TextBlock tb = new TextBlock();
                    tb.Text = numbers[i * 9 + j].ToString();
                    tb.HorizontalAlignment = HorizontalAlignment.Center;
                    tb.VerticalAlignment = VerticalAlignment.Center;
                    Grid.SetRow(tb, i);
                    Grid.SetColumn(tb, j);

                    Thickness thk = new Thickness(0, 0, 0, 0);
                    if (i == 2 || i == 5)
                    {
                        thk.Bottom = 1;
                    }
                    if (i == 3 || i == 6)
                    {
                        thk.Top = 1;
                    }
                    if (j == 2 || j == 5)
                    {
                        thk.Right = 1;
                    }
                    if (j == 3 || j == 6)
                    {
                        thk.Left = 1;
                    }
                    Border border = new Border();
                    border.BorderThickness = thk;
                    border.BorderBrush = Brushes.Black;
                    Grid.SetRow(border, i);
                    Grid.SetColumn(border, j);

                    window.Grid1.Children.Add(border);
                    window.Grid1.Children.Add(tb);

                    window.TextBlocks[i * 9 + j] = tb;
                }
            }
            window.Show();
            return window;
        }


    }
}

Dies wird nun benutzt um das Sudoku anzuzeigen. Das Löseprogramm zeigt das aktuelle Sudoku und öffnet für jede gefundene Lösung ein neues Fenster. MainWindow ist leer, wird lediglich zum Starten des Programmes benötigt.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SudokuSolver
{
    /// <summary>
   /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Thread thread = new Thread(workLoop);
            thread.Start();
        }

        private SudokuShowWindow window;
        private int numberCounter;
        private int[] initialNumbers;
        private int[] numbers;
        List<int[]> Solutions = new List<int[]>();

        private void workLoop()
        {
            //The initial Sudoku which should be solved
            initialNumbers = new int[81]
            {
                5,3,0,   0,7,0,   0,0,0,
                6,0,0,   1,9,5,   0,0,0,
                0,9,8,   0,0,0,   0,6,0,

                8,0,0,   0,6,0,   0,0,3,
                4,0,0,   8,0,3,   0,0,1,
                7,0,0,   0,2,0,   0,0,6,

                0,6,0,   0,0,0,   2,8,0,
                0,0,0,   4,1,9,   0,0,5,
                0,0,0,   0,8,0,   0,7,9
            };
            numbers = new int[81];
            for (int i = 0; i < 81; i++)
            {
                numbers[i] = 0;
            }

            //Invoke window actions because we are not in the main thread
            Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                window = SudokuShowWindow.newSudokuShowWindow(initialNumbers);
            }));

            //Position of the "cursor" in the sudoku
            numberCounter = 0;

            int ctr = 0;
            bool noi = false;


            while (true)
            {
                if (isItValid())
                {
                    noi = false;

                    //A valid solution!
                    if (numberCounter > 80)
                    {
                        int[] totalNumbers = new int[81];
                        for (int i = 0; i < 81; i++)
                        {
                            totalNumbers[i] = initialNumbers[i];
                            if (totalNumbers[i] == 0)
                            {
                                totalNumbers[i] = numbers[i];
                            }
                        }

                        bool eq = false;
                        foreach (int[] solution in Solutions)
                        {
                            bool leq = true;
                            for (int i = 0; i < 81; i++)
                            {
                                if (solution[i] != totalNumbers[i])
                                {
                                    leq = false;
                                }
                            }
                            if (leq)
                            {
                                eq = true;
                            }

                        }
                        if (!eq)
                        {
                            int[] tmp = new int[81];
                            for (int i = 0; i < 81; i++)
                            {
                                tmp[i] = totalNumbers[i];
                            }
                            Solutions.Add(tmp);
                        }
                        else
                        {
                            System.Console.WriteLine("Done!");
                            break;
                        }

                        Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            SudokuShowWindow.newSudokuShowWindow(totalNumbers);
                        }));

                        //Check for other solutions?

                        noi = true;
                        while (true)
                        {
                            numberCounter--;
                            if (initialNumbers[numberCounter] == 0)
                            {
                                if (numbers[numberCounter] >= 9)
                                {
                                    numbers[numberCounter] = 0;
                                }
                                else
                                {
                                    numbers[numberCounter]++;
                                    break;
                                }
                            }
                        }
                    }

                    if (numberCounter > 80)
                    {
                        break;
                    }

                    if (numbers[numberCounter] == 0 && initialNumbers[numberCounter] == 0)
                    {
                        iterateOne();
                    }
                    else
                    {
                        if (!noi)
                        {
                            increaseNumberCounter();
                        }
                    }
                }
                else
                {
                    if (numberCounter > 80 || numberCounter < 0)
                    {
                        break;
                    }
                    if (numbers[numberCounter] >= 9)
                    {
                        decreaseOne();
                        Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            int[] totalNumbers = new int[81];
                            for (int i = 0; i < 81; i++)
                            {
                                totalNumbers[i] = initialNumbers[i];
                                if (totalNumbers[i] == 0)
                                {
                                    totalNumbers[i] = numbers[i];
                                }
                            }
                            window.refreshValues(totalNumbers);
                        }));

                    }
                    else
                    {
                        iterateOne();
                    }
                }
                ctr++;
                if (ctr > 1000)
                {
                    ctr = 0;
                    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        int[] totalNumbers = new int[81];
                        for (int i = 0; i < 81; i++)
                        {
                            totalNumbers[i] = initialNumbers[i];
                            if (totalNumbers[i] == 0)
                            {
                                totalNumbers[i] = numbers[i];
                            }
                        }
                        window.refreshValues(totalNumbers);
                    }));
                    Thread.Sleep(1);
                }
            }
            Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                window.Close();
            }));
        }

        void increaseNumberCounter()
        {
            numberCounter++;
            while (numberCounter <= 80 && initialNumbers[numberCounter] != 0)
            {
                numberCounter++;
            }
        }

        void iterateOne()
        {
            if (numberCounter > 80)
            {
                return;
            }
            while (initialNumbers[numberCounter] != 0)
            {
                numberCounter++;
            }
            numbers[numberCounter]++;
        }

        void decreaseOne()
        {
            if (numberCounter > 80)
            {
                numberCounter = 80;
            }
            numbers[numberCounter] = 0;
            if (numberCounter == 0)
            {
                return;
            }

            while (numberCounter >= 0)
            {
                numberCounter--;
                while (numberCounter > 0 && initialNumbers[numberCounter] != 0)
                {
                    numberCounter--;
                }
                if (numberCounter < 0)
                {
                    return;
                }
                if (numbers[numberCounter] < 9)
                {
                    numbers[numberCounter]++;
                    return;
                }
                else
                {
                    numbers[numberCounter] = 0;
                }
            }
        }

        bool isItValid()
        {
            int[] totalNumbers = new int[81];
            for (int i = 0; i < 81; i++)
            {
                totalNumbers[i] = initialNumbers[i];
                if (totalNumbers[i] == 0)
                {
                    totalNumbers[i] = numbers[i];
                }
            }
            //Check Horizontal
            List<int> testList;
            for (int i = 0; i < 9; i++)
            {
                testList = new List<int>();
                for (int j = 0; j < 9; j++)
                {
                    if (testList.Contains(totalNumbers[i * 9 + j]))
                    {
                        //Invalid
                        return false;
                    }
                    if (totalNumbers[i * 9 + j] != 0)
                    {
                        testList.Add(totalNumbers[i * 9 + j]);
                    }
                }
            }

            //Check Vertical
            for (int j = 0; j < 9; j++)
            {
                testList = new List<int>();
                for (int i = 0; i < 9; i++)
                {
                    if (testList.Contains(totalNumbers[i * 9 + j]))
                    {
                        //Invalid
                        return false;
                    }
                    if (totalNumbers[i * 9 + j] != 0)
                    {
                        testList.Add(totalNumbers[i * 9 + j]);
                    }
                }
            }
            //Check squares
            for (int ii = 0; ii < 3; ii++)
            {
                for (int jj = 0; jj < 3; jj++)
                {
                    testList = new List<int>();
                    for (int i = ii * 3; i < ii * 3 + 3; i++)
                    {
                        for (int j = jj * 3; j < jj * 3 + 3; j++)
                        {
                            if (testList.Contains(totalNumbers[i * 9 + j]))
                            {
                                //Invalid
                                return false;
                            }
                            if (totalNumbers[i * 9 + j] != 0)
                            {
                                testList.Add(totalNumbers[i * 9 + j]);
                            }
                        }
                    }
                }
            }
            //Valid
            return true;
        }
    }
}

Visual Studio - Anwendung mit automatischen Updates benötigt lange zum Starten

(English version) Wenn man in Visual Studio ein Projekt veröffentlicht und dann die Anwendung startet wird normalerweise zuerst nach Updates gesucht. Dies kann einige Zeit in Anspruch nehmen und ist nervig wenn man die Anwendung möglichst schnell haben will. Glücklicherweise kann man den Zeitpunkt der Updates umstellen, sodass erst nach Updates geprüft wird, wenn die Anwendung schon gestartet ist. Die Updates kann man dann beim nächsten Start installieren ohne lange Wartezeiten zu haben.

Um dies einzustellen muss man in die Projekteigenschaften gehen. Hier gibt es dann den Unterpunkt "Veröffentlichen", wo es dann die Schaltfläche "Updates" gibt. Hier ist man dann auch bei der gewünschten Einstellung: "Zeitpunkt für Updateüberprüfungen auswählen". Hier ist standartmäßig "Vor Start der Anwendung" ausgewählt, um die Startzeit zu verkürzen muss man nun "Nach dem Starten der Anwendung" auswählen.

Speichernutzung übersichtlich anzeigen - WinDirStat

(English version) Bei zunehmender Datenmenge wird es immer schwieriger, die Datenmengen zu kontrollieren und so passiert es immer öfter dass die Festplatte voll ist und man eigentlich keine Ahnung hat was die Speicherfresser sind. Um dieses Problem anzugehen gibt es ein sehr nützlichen Programm: WinDirStat.

Dieses Programm zeigt die Speichernutzung einer Partition sehr übersichtlich an, wie man im folgenden Bild sehen kan:
Man kann Ordner auswählen und sieht sofort einen weißen Rahmen der den Speicherplatz des gesamten Ordners anzeigt. Jede Datei entspricht einem Rechteck, sodass man einzelne große Dateien sofort ausmachen kann. Ich persönlich habe mit diesem Programm bereits einige viele Gigabyte an unnötigen Daten gelöscht und kann es nur jedem weiterempfehlen.

Sonntag, 31. August 2014

Spannung überwachen am Arduino, ATmega oder ATtiny

(English version)
Wer seinen Arduino oder einen ATmega bzw. ATtiny über eine Batterie mit Spannung versorgt muss immer damit rechnen, dass die irgendwann einmal leer ist und dann der Mikrocontroller ohne Vorwarnung den Dienst einstellt. Hier ist es hilfreich, die Versorgungsspannung zu überwachen. Sollte sie unter einen bestimmten kritischen Wert fallen, kann man sich zum Beispiel durch anschalten einer LED warnen lassen.
Die Überwachung der Spannung kann ohne zusätzliche Hardware erfolgen. Möglich macht es der AD-Wandler. Dieser arbeitet ja bekannterweise nach folgender Formel:
WERT_ADC = V_EINGANG * 1023/V_REFERENZ
Nun könnte man natürlich meinen: "Ich lege einfach meine Versorgungsspannung an den Eingang des AD-Wandlers und kann diese so messen". Das funktioniert leider nicht, da die Referenzspannung des AD-Wandler ebenfalls die Versorgungsspannung ist. Der Wert des AD-Wandlers wäre als immer 1023.
Doch es gibt einen Trick: jeder Mikrocontroller erzeugt eine interne Referenzspannung, die so genannte "Bandgap Voltage" V_BG. Diese beträgt beim ATmega328, der im Arduino Uno zum Einsatz kommt, 1.1V.  Diese Spannung lässt sich auf den Eingang des AD-Wandlers legen. mit V_EINGANG = V_BG und V_REFERENZ = V_CC ergibt sich dann:
WERT_ADC = V_BG * 1023/V_CC
oder umgeformt:
V_CC = V_BG * 1023/WERT_ADC
Setzt man nun ein V_BG = 1100 (in mV) ergibt sich:
V_CC = 1100 * 1023/WERT_ADC
V_CC ist nun der Wert der Spannungsversorgung in mV

Umgesetzt in Code sieht das dann so aus:

int led = 13;  //Pin der LED
int adc_low, adc_high;  //Zwischenspeicher für die Ergebnisse des ADC
long adc_result;  //Gesamtergebnis der Messung des ADC
long vcc;  //Versorgungsspannung

void setup() {    
  pinMode(led, OUTPUT);  

  ADMUX |= (1<<REFS0); //VCC als Referenzspannung für den AD-Wandler
  ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung als Eingang für ADC 
  delay(10);  //warten bis sich die Referenzspannung eingestellt hat
  ADCSRA |= (1<<ADEN);   //ADC aktivieren
}

// the loop routine runs over and over again forever:
void loop() {    
  ADCSRA |= (1<<ADSC);  //Messung starten

  while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
  //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
  adc_low = ADCL;
  adc_high = ADCH;

  adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
  vcc = 1125300L / adc_result;  //Versorgungsspannung in mV berechnen (1100mV * 1023 = 1125300)

  //wenn Spannung kleiner als 5V 
  if (vcc < 5000)
  {
    digitalWrite(led, HIGH);  //schalte LED an
  }
  //wenn größer oder gleich 5V
  else 
  {
    digitalWrite(led, LOW);  //schalte LED aus
  }

  delay(500);
}


In der setup()-Funktion wird zuerst der AD-Wandler so eingestellt, dass zum einen die Versorgungsspannung V_CC als Referenz und zum anderen die Bandgap-Spannung V_BG als Eingang für den AD-Wandler dienen. Nach einer kurzen Wartezeit wird der AD-Wandler dann aktiviert.
In der loop() wird dann die Messung durch setzen des Bits ADSC gestartet. Ist die Messung beendet (ADSC ist wieder 0) wird das Ergebnis der Wandlung aus den Registern ADCL (die unteren 8 Bit) und ADCH (die oberen 2 Bit) ausgelesen und zu einem 10-Bit-Ergebnis zusammengesetzt. Aus diesem wird dann nach der obigen Formel die Versorgungsspannung bestimmt. Liegt sie unter 5V, wird eine LED eingeschaltet.

Diese Methode funktioniert prinzipiell mit allen ATmegas oder ATtinys. Je nach verwendetem µC müssen allerdings in den Registern des AD-Wandlers andere Bits gesetzt werden. Welche das genau sind, kann dem Datenblatt entnommen werden.

Mittwoch, 20. August 2014

ATmega - Bodenfeuchte von Zimmerpflanzen messen

(English version) Heute möchte ich vorstellen, wie man einen Feuchtigkeitssensor baut und ansteuert. Die Grundidee dahinter ist, zu messen wie feucht die Erde einer Pflanze ist und dann dementsprechend zu wissen wann man gießen muss.

Für den Bau des Sensors wird nicht viel benötigt. Ich habe ein kleines Stück Streifenrasterplatine, 2 Nägel und Stiftleisten benutzt. Der Sensor sieht dann so aus:
Nun misst man den Widerstand zwischen den zwei Nägeln (wenn der Sensor in der Erde steckt) und schon kann man Rückschlüsse auf die Bodenfeuchte ziehen. In der Schaltung sieht das dann folgendermaßen aus:
Bei feuchter Erde leiter der Sensor gut, also misst der ATmega eine hohe Spannung (zu interpretieren als Erde ist feucht). Bei trockener Erde steigt der Widerstand, daher sinkt die gemessene Spannung. Natürlich kann man jetzt noch überlegen welche Einheiten die Achsen bekommen und so weiter, ich denke jedoch es ist sinniger, einfach 0 bis 5 V aufzutragen (oder 0 bis 100%) und dann selbst zu überprüfen wann die Pflanze gegossen werden muss - dies ist dann der Wert bei dessen Unterschreitung eine rote Lampe an geht oder eine automatische E-Mail gesendet wird.

Montag, 9. Juni 2014

Helligkeitssensor BH1750FVI

(English version) Für mein "Home Automation"-Projekt habe ich auch eine Automatisierung des Rollladens geplant. Dabei soll der Rollladen geschlossen werden, wenn die Sonne ins Zimmer scheint um so ein Aufheizen des Zimmers zu verhindern. Um Sonneneinstrahlung zu erkennen verfolge ich im Moment zwei Ansätze: Erkennung über Helligkeit und Temperatur.

Zur Erkennung der Sonneneinstrahlung über die Helligkeit setze ich einen Helligkeitssensor vom Typ BH1750FVI ein. Dieser ist (wie so oft) für unter 2 Euro bei Ebay erhältlich.

Der Sensor misst die Helligkeit zwischen 0 und 65535 lx und schickt das Ergebnis der Messung über den I2C-Bus an den Mikrocontroller. Die Messung der Helligkeit kann kontinuierlich oder einmalig mit einer Auflösung von 0.5, 1 oder 4 lx erfolgen.

Die Ansteuerung des Sensors bzw. die Abfrage der Helligkeit über I2C funktioniert "von Hand" schon ziemlich einfach, noch komfortabler wird es jedoch mit dem Arduino unter Verwendung der passenden Library. Ich habe die Lib von Christopher Laws verwendet.

Der Sensor wird einfach über VCC und GND mit 5V verbunden, SDA und SCL werden an die entsprechenden Pins des Arduino, ATmega oder ATtiny angeschlossen.

Dann kann der Beispiel-Code der Library übertragen werden:
#include <Wire.h>
#include <BH1750.h>

BH1750 lightMeter;

void setup(){
  Serial.begin(9600);
  lightMeter.begin();
  Serial.println("Running...");
}


void loop() {
  uint16_t lux = lightMeter.readLightLevel();
  Serial.print("Light: ");
  Serial.print(lux);
  Serial.println(" lx");
  delay(1000);
} 
 
Der Code ist weitestgehend selbsterklärend. Im Setup wird der Sensor mit der begin()-Funktion initialisiert. Wenn gewünscht kann hier durch Übergabe eines entsprechenden Parameters der Mess-Modus (einmalig/kontinuierlich bzw. die Auflösung) eingestellt werden. Näheres dazu ist dem h-File der Library zu entnehmen. Der aktuelle Helligkeitswert in Lux kann dann über die Funktion readLightLevel() ausgelesen werden. Und das war es auch schon, mehr gibts dazu nicht zu sagen ;)