C# Weather Station with Datalogger

C# Weather Station with Datalogger

A while ago, we created a weather station in PHP based on a Yocto-Humidity module. Today, we have a new version in C# which improves the concept by exploiting the data logger integrated into the Yocto-Meteo, a module which is an improved version of the product used for the previous article.




The main problem of the previous example was that if the computer was off or restarting, the weather data were not recorded. In a world where Windows updates are very frequent, this can become an issue. The idea is then to delegate data recording to the module itself, rather than to do it on the computer which displays the data. Thus, even if in the middle of the night, your computer decides to restart to update its OS, and that the update crashes (it happened!), the module continues to record the data. When you finally succeed in correctly restarting you OS 4 hours and 10 patches later, you'll still have the weather data of what happened during these 4 hours ... It's the first advantage of the data logger.

The second advantage is that, if it is not necessary to constantly display the graphic, you can stop your application and let the module alone record and store the data, without using CPU time on your computer.

We have spent a large number of articles explaining in details your programs. For once, we concentrate on how to use the data logger.

The first step is to start the automatic data recording. Let's suppose that the datalogger variable is already correctly initialized (using YDataLogger.FirstDataLogger() or YDataLogger.FirstDataLogger()) and that it references a YDataLogger object.

First of all, we must configure the module to automatically start recording as soon as it is powered on, even if the computer doesn't communicate with it. As this is a persistent parameter, we need two steps to achieve this:

    dataLogger.set_autoStart(YDataLogger.AUTOSTART_ON);
    dataLogger.module().saveToFlash();



Then, we set the time of the module: the module is not powered by a battery, you must set its time after each power off.

    DateTime now = DateTime.UtcNow;
    TimeSpan span = (now - new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime());
    dataLogger.set_timeUTC((int)span.TotalSeconds);



Finally, the call to set_recording(YDataLogger.RECORDING_ON) starts data recording.

    dataLogger.set_recording(YDataLogger.RECORDING_ON);



From then on, and as long as the module is powered, the module flash memory fills up with new data.


Now, we need to retrieve the data from the module. First, we must download the index of the flash memory:

    List<YDataStream> dataStreams = new List<YDataStream>();
    dataLogger.get_dataStreams(dataStreams);




As downloading all the data can be time consuming and can involve a very large quantity of data to be processed, we are going to download only the data of the last two days, as a background task.

for (int i = startfrom; i < dataStreams.Count; i++)
{
    YDataStream stream = dataStreams[i];
    int progress = (i - startfrom) * 100 / (dataStreams.Count - startfrom);
    backgroundWorker1.ReportProgress(progress, "Loading " + dataLogger.module());
    // drop data that do not have a timestamp
    long unixtime = stream.get_startTimeUTC();
    if (unixtime == 0)
        continue;

    long utc = stream.get_startTimeUTC();
    DateTime tstart = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(utc);

    Stopwatch sw = new Stopwatch();
    DateTime tend = tstart.AddSeconds(stream.get_rowCount() * stream.get_dataSamplesInterval());

    List<String> names = stream.get_columnNames();
    int increment = 1;
    if (stream.get_dataSamplesInterval() == 1)
    {
        // we take only one mesure per minute
        increment = 60;
    }

    for (int row = 0; row < stream.get_rowCount(); row += increment)
    {
        long nbsec = unixtime + row * stream.get_dataSamplesInterval();
        DateTime t = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(nbsec);
        TimeSpan delta = DateTime.Now - t;
        if (delta.TotalDays > 2)
        {
            continue;
        }
        DataRow rowData = table.NewRow();
        rowData["Time"] = t;
        for (int c = 0; c < stream.get_columnCount(); c++)
        {
            switch (names[c])
            {
                case "temperature":
                    rowData["Temperature"] = stream.get_data(row, c);
                    break;
                case "pressure":
                    rowData["Pressure"] = stream.get_data(row, c);
                    break;
                case "humidity":
                    rowData["Humidity"] = stream.get_data(row, c);
                    break;
                default:
                    continue;
            }
        }
        table.Rows.Add(rowData);
    }
}



Finally, most of the code consists in drawing the graphic in the interface, using the data that we have downloaded.

Here is a screen shot of the application
Here is a screen shot of the application



PS: the application will be include in the next version of the library

Add a comment No comment yet Back to blog












Yoctopuce, get your stuff connected.