Arduino and sensors on bench in front of seedlings in plastic containers.

Arduino Greenhouse

An amalgamation of arduino, C++, Windows, C#, Django, rest and internet technologies.

I've always wanted to experiment with gathering my own sensor data. My recent purchase of an Arduino let me work on this. The set up is kind of convoluted. I had an old Windows tablet laying around and I wanted to use it for the display for the arduino (instead of buying a new lcd for it). This forced me to build a gui to run on windows. I chose C#/WPF to build the gui.

The tablet left a little to be desired. I didn't want it on all the time, but going through the hassle of logging in every time I wanted to see data got to me, so I decided to upload the data to my server and build a page here to display the data. That had the extra benefit of allowing me to check from any room in the house.

The c++ code on the arduino is very simple and it shares data with the windows tablet via serial port.

Conditions indicators of the arduino greenhouse
published: 3/8/20 12:12 p.m.

https

So, this morning I was surprised to wake up and discover my device had not updated in 3 hours. I tried to turn it off and on again, that didn't solve the problem, but at least the LEDs flickered on for half a second indicating it did have power and was likely working.

My first thought was that the website security certificate may have changed. So I followed up turning it off and on again with checking the /var/log/nginx/access.log which stated the following at 10:12:16 GMT

[08/Mar/2020:10:12:15 +0000] "POST /garden/api/readings.json/ HTTP/1.1" 201 113 "-" "ESP8266HTTPClient"
2600:1f16:269:da01:4e9f:c9d7:3ffe:6166 - - [08/Mar/2020:10:12:16 +0000] "GET /.well-known/acme-challenge/WrEvWgDp4cNpjjLpjglSja
1I90YFgAxTkW68YjoR2z4 HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.
org)"
2600:1f16:269:da01:4e9f:c9d7:3ffe:6166 - - [08/Mar/2020:10:12:16 +0000] "GET /.well-known/acme-challenge/ytSN6CxKtvhV19wks2bomt
q8ph6XdF6L7KjDA34aVso HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.
org)"

08/Mar/2020:10:12:15 +0000 was the time of my last successful update. I believe the next connection was from Let's Encrypt verifying that the update was successful.

I checked the certificate in my browser and it had this information at the bottom.

**Timestamp** 3/8/2020, 6:12:50 AM (Eastern Daylight Time)
**Signature Algorithm** SHA-256 ECDSA

I believe this was Let's Encrypt auto updating my certificate this morning. This is a month ahead of schedule, which reinforces that I don't know how that process works.

The issue is that the ESP2866 doesn't quite have the capability to connect to https servers. Or it does, but it requires a work around. I hard coded the SHA-1 fingerprint into the sketch. It wasn't ideal, it wasn't exactly what I wanted to do, but, I believed the certificate was good for another month, so it would work for the planned life of the project.

This morning, I will need to update the fingerprint on the sketch. I may change to using the root certificate which has a much longer life time. I may try to set a system up that auto updates the fingerprint.

Close up of ESP8266
published: 3/6/20 4:04 a.m.

ESP8266

The arduino garden project has taken a turn.

The ESP8266 is a board similar to the arduino but with a built in wifi chip. They are also very inexpensive. I was able to get three for the price of a single arduino duo.

The ESP opens up a lot of possibilities. MQTT is a message queuing system that uses wifi allowing subsciptions would allow a bunch of sensors to communicate with each other, or a central system. But for the greenhouse project I'd be able to log the info directly to the server and skip the tablet all together.

Earlier today, while I was thinking that this solves a bunch of "problems" the electricity went out. The EPS, which I was testing at the time, was suddenly unable to upload because it no longer had access to wifi. Which is bringing me to the issues I'm currently thinking over. What do I do about data? Should I store the data on the chip, or locally somehow and then check to see if the server has it from time to time and then upload old data. For this project that's overkill, but it seems like an important question.

ESP8266 pinout

Design layout of greenhouse app
published: 3/2/20 7:07 p.m.

XAML

I started the C# of the project in a WinForms kind of place. The windows and code were tightly linked. I spent part of last week reworking the code to separate the project into a mvvm pattern. It's more work, but I find it very comforting that I can just delete a window and start over. I still need to create some converters to display the Unix Timestamp as a date. I would like to add charts in the next iteration.

<Window x:Class="Arduino_Greenhouse.View.DisplayWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Arduino_Greenhouse.View"
        xmlns:vm="clr-namespace:Arduino_Greenhouse.ViewModel"
        mc:Ignorable="d"
        Title="DisplayWindow"
        WindowState="Maximized" d:DesignWidth="1642.688" d:DesignHeight="763.75"
        >
    <Window.Resources>
        <vm:DisplayVM x:Key="vm"/>
    </Window.Resources>

    <Grid DataContext="{StaticResource vm}">
        <Grid.RowDefinitions>
            <RowDefinition Height="3*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.Background>
            <LinearGradientBrush EndPoint="0,0" StartPoint="1,1">
                <GradientStop Color="#fff2ab" Offset="0.88" />
                <GradientStop Color="#99da8f" Offset="0.33" />
                <GradientStop Color="#9382bb" Offset="0" />
            </LinearGradientBrush>
        </Grid.Background>

        <!--<Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>-->
        <Grid 
        Margin="50"
            VerticalAlignment="Center"
            HorizontalAlignment="Stretch"
            >

            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>

            <StackPanel Grid.Column="0" Width="Auto" >
                <TextBlock Text="Environment" FontSize="48" TextAlignment="Center"/>
                <TextBlock Text="{Binding sensorReading.temp1, StringFormat={}{0:f1} °F}" FontSize="48" TextAlignment="Center"/>
                <TextBlock Text="{Binding sensorReading.rh1, StringFormat={}{0}% RH}" FontSize="48" TextAlignment="Center"/>
            </StackPanel>
            <StackPanel Grid.Column="1" Width="Auto">
                <TextBlock Text="Greenhouse" FontSize="48" TextAlignment="Center"/>
                <TextBlock Text="{Binding sensorReading.temp2, StringFormat={}{0:f1} °F}" FontSize="48" TextAlignment="Center" />
                <TextBlock Text="{Binding sensorReading.rh2, StringFormat={}{0}% RH}" FontSize="48" TextAlignment="Center" />
            </StackPanel>
            <StackPanel Grid.Column="3" Grid.Row="0" Width="Auto">
                <TextBlock Text="Conditions" FontSize="48" TextAlignment="Center"/>
                <TextBlock Text="{Binding sensorReading.light, StringFormat=Light: {0}}"   FontSize="48" TextAlignment="Center" />
                <TextBlock Text="{Binding sensorReading.timestamp, StringFormat={}Time: {0:f1}}" FontSize="48" TextAlignment="Center"/>
            </StackPanel>
        </Grid>
        <!--
            Here lies the connection buttons
        -->
        <StackPanel Orientation="Horizontal" Grid.Row="2" DataContext="{StaticResource vm}">
            <Button x:Name="btnGetPorts" 
                    Content="Get Ports" 
                    HorizontalAlignment="Left" Margin="10" Grid.Row="1" VerticalAlignment="Center" Width="75" 
                    Command="{Binding GetComPortsCommand}"
                    />
            <ComboBox x:Name="cboPorts"
                      ItemsSource="{Binding ComPortList, NotifyOnSourceUpdated=True}"
                      SelectedIndex="0"
                      SelectedItem="{Binding SelectedComPort, UpdateSourceTrigger=PropertyChanged}"
                      HorizontalAlignment="Left" Margin="10" Grid.Row="1" VerticalAlignment="Center" 
                      Width="120" RenderTransformOrigin="0.777,2.853"/>
            <Button  x:Name="btnConnect" 
                     Command="{Binding ConnectToArduinoCommand}"
                     CommandParameter="{Binding SelectedComPort}"
                     Content="{Binding ConnectButtonContent, NotifyOnSourceUpdated=True}"
                     HorizontalAlignment="Left" Margin="10" Grid.Row="1" VerticalAlignment="Center" Width="75">

            </Button>
            <CheckBox x:Name="cbUpload" Content="Upload to server" HorizontalAlignment="Left" Margin="10" Grid.Row="1"  VerticalAlignment="Center" />
        </StackPanel>


    </Grid>
</Window>