Luftqualitäts-Monitor + Windows App
Allgemeine Informationen
Der Luftqualitäts-Monitor besteht aus einer Platine mit den entsprechenden Bauteilen und kann über eine Windowsapp konfiguriert und visualisiert werden.
Sämtliche Quellcodes wurde von uns selbst entworfen.
Das ganze Projekt ist schon etwas älter und wurde zu Corona-Anfangszeiten entwickelt.
Hintergrund bzw. die angedachte Funktionsweise war die Ermittlung der Anzahl an organischen Teilchen in der Atemluft.
Mit dieser Information und der u. a. grafischen Darstellung der Werte, konnte der richtige Zeitpunkt für das Lüften des Raumes ermittelt werden.
Dadurch sollte eine größere Belastung durch die Atemluft mit Corona-Viren gemindert werden.
Die App sowie das Arduino Projekt könnt Ihr direkt von unserer Seite downloaden.
Euch steht natürlich frei, die ganzen Elemente nach euren Interessen anzupassen.
Viel Spaß beim Nachbauen oder Umbauen.
Inhaltsverzeichnis
Hardware
Auflistung aller Hardware-Komponenten und dem zugehörigen Schaltplan.
Im Download-Bereich könnt Ihr den Schaltplan als KiCad-Projekt herunterladen.
Die Bilder können durch einen Mausklick vergrößert werden.
Bauteile
Software
Über die Software können die Hardwareeinstellungen vorgenommen werden.
Zusätzlich kann der Verlauf aller Werte in einem Diagramm dargestellt werden.
Hierzu muss das Modul mit einem PC über USB verbunden werden.
Im Anschluss kann die Software gestartet werden.
Die Software ermittelt eigenständig die Com-Schnittstelle und baut eine Verbindung auf.
Mit dem Dropdown Menü am linken unteren Rand, kann zwischen den verschiedenen Funktionen der Software umgeschaltet werden.
- Konfiguration anpassen
- CO₂ (parts per million)
- TVOC (Gesamtkonzentration flüchtigen organischen Verbindungen)
- Temperatur in °C
- Relative Feuchte rF%
Konfiguration anpassen
Mit einem Klick auf die Grüne- oder Rot-Fläche, werden diese markiert.
Hierbei nimmt auch der Zahlenwert in der Mitte die jeweilige Farbe an.
Ein Klick auf die Zahl zwischen + und -, ändert die Schrittgröße.
Über Plus und Minus lassen sich nun die Schaltschwellen der LED`s einstellen.
Maßgebend ist hierbei der CO₂-Wert.
Auf die gleiche Weise lassen sich die Min- und Max-Werte (im Bild 800 und 1700) verändert. Hierzu muss aber auf das jeweilige Textfeld geklickt werden.
Alle Einstellungen werden, mit dem Button ‚Speichern‘, auf dem EEPROM gespeichert.
Über Abbruch, werden die Daten aus dem Speicher wieder in das Programm geladen.
CO2 (parts per million)
Der CO2-Gehalt in der Luft wird in parts per million (Anteile pro Million), kurz ppm, oder in Prozent (%), beziehungsweise Volumenprozent (Vol. -%) angegeben.
Welcher CO2 Wert ist normal?
Danach gelten Konzentrationen unter 1000 ppm Kohlendioxid in der Raumluft als unbedenklich, Konzentrationen zwi- schen 1000 und 2000 ppm als auffällig und Konzentrationen über 2000 ppm als in- akzeptabel.
Je nach eingestellten Grenzwerten (siehe Konfiguration anpassen), werden in diesem Diagramm die Schaltschwellen der LEDs eingeblendet. Hierbei gilt: Unter Grün, leuchtet die Grüne LED. Zwischen Grün und der roten Linie die gelbe LED. Über der roten Linie, die rote LED.
TVOC (Gesamtkonzentration flüchtigen organischen Verbindungen)
Die Gesamtkonzentration flüchtigen organischen Verbindungen (TVOC) in ppb (Teile pro Milliarde) ist die Summe aus Hunderten verschiedenen flüchtigen organischen Verbindungen in Innenräumen, deren Zusammensetzung sich ständig verändert.
Die TVOC-Konzentration kann nur durch die Analyse aller einzelnen Verbindungen gemessen werden, beispielsweise durch eine Gaschromatographie und Massenspektrometrie (GC-MS).
Relative Feuchte rF%
Was ist relative Luftfeuchtigkeit? Die relative Luftfeuchtigkeit gibt Aufschluss darüber, wie viel Prozent die Luft mit Wasser(dampf) gesättigt ist. Grundsätzlich gilt: je wärmer die Lufttemperatur, desto mehr Wasser kann diese aufnehmen. Bei 100% relativer Feuchte ist die Luft vollständig mit Wasser(dampf) gesättigt.
Quellcode Luftqualitäts-Monitor Windows APP
Das Programm wurde in der Programmiersprache VB.net geschrieben. Der Quellcode wird durch das Einbinden in die Homepage automatisch angepasst. Es werden z. B. Zeilenumbrüche eingefügt. Er kann somit nicht 1 zu 1 in dein Visual Studio Projekt übernommen werden. Visual Studio ist eine von dem Unternehmen Microsoft angebotene integrierte Entwicklungsumgebung für verschiedene Hochsprachen. Gerne könnt das Programm über den Download-Bereich herunterladen. Wollt Ihr jedoch das Visual Studio Projekt, würde ich euch bitten, mir eine Nachricht über das Kontaktformular zukommen zu lassen. Ich melde ich dann per E-Mail bei euch.
Imports System.IO.Ports 'Serielle Schnittstellen import
Imports System.Windows.Forms.DataVisualization.Charting
Public Class C02WarnForm
#Region "Globale Variablen"
Dim arrComlist As New ArrayList
Dim intBootCount As Integer = 0 'Definiert den Bootschritt
Dim intDeviceFound As Integer = 0 'Gerät gefunden = 1
Dim intActDevice As Integer = 0 'Aktuelles Gerät das verbunden werden soll
Dim intGrenzWert1 As Integer 'Grenzwert default Werte
Dim intGrenzWert2 As Integer 'Grenzwert default Werte
#End Region
#Region "Form laden"
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
UpdateTxtStatus("Ermittle alle verfügbaren Com-Schnittstellen...", False)
cboChartTyp.SelectedIndex = 0
BootTimer.Enabled = True
End Sub
#End Region
#Region "Bootvorgang"
Private Sub BootTimer_Tick(sender As Object, e As EventArgs) Handles BootTimer.Tick
If intBootCount = 0 Then
BootTimer.Enabled = False
GetAllCom()
BootTimer.Interval = 4000
BootTimer.Enabled = True
intBootCount = 1
ElseIf intBootCount = 1 Then
CheckComForDevice()
ElseIf intBootCount = 2 Then
Application.Exit()
End If
End Sub
Private Sub GetAllCom()
For Each strPortDevice In My.Computer.Ports.SerialPortNames
On Error Resume Next
SerialPort.PortName = strPortDevice
SerialPort.Open()
If SerialPort.IsOpen Then
UpdateTxtStatus(strPortDevice & " als möglich Schnittstelle gefunden.", False)
SerialPort.Close()
arrComlist.Add(strPortDevice)
End If
Next
End Sub
Private Sub CheckComForDevice()
If ((intDeviceFound = 0) And (intActDevice < arrComlist.Count.ToString)) Then
If SerialPort.IsOpen = True Then
SerialPort = New SerialPort
SerialPort.BaudRate = 115200
SerialPort.Close()
End If
SerialPort.PortName = arrComlist(intActDevice)
SerialPort.Open()
UpdateTxtStatus("Verbindung Aufgebaut zu " & arrComlist(intActDevice) & ". Warte auf Verifizierung.", False)
intActDevice += 1
Else
intBootCount = 2
BootTimer.Interval = 4000
UpdateTxtStatus("Gerät nicht gefunden! Anwendung wird in 4 Sekunden beendet!", True)
End If
End Sub
#End Region
#Region "Empfange serielle Daten"
Private Sub SerialPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialPort.DataReceived 'Bei Datenempfang über serielle Verbindung Kamera
Dim strDataRec As String = ""
Try
Do Until strDataRec.Contains(vbCrLf) Or strDataRec.Contains(vbCr)
strDataRec &= SerialPort.ReadExisting
Loop
Catch ex As Exception
MsgBox(ex.Message)
End Try
strDataRec = strDataRec.Replace(vbCrLf, "").Replace(Chr(29), "").Replace(vbCr, "")
Me.Invoke(Sub() Call DataRecive(strDataRec))
SerialPort.DiscardInBuffer()
End Sub
Private Sub DataRecive(strReciveValue As String)
If ((strReciveValue.Contains("#CO2-OK;")) And (intDeviceFound = 0)) Then
BootTimer.Enabled = False
UpdateTxtStatus("Verbindung zum Gerät hergestellt...", False)
SerialPort.Write("#CO2-D;")
UpdateTxtStatus("Anfrage Grenzwerte...", False)
intDeviceFound = 1
ButtonControl(0, Color.White)
ElseIf ((strReciveValue.Contains("#CO2-D,")) And (intDeviceFound = 1)) Then
strReciveValue = strReciveValue.Replace("#CO2-D,", "").Replace(";", "")
UpdateTxtStatus("Grenzwerte Empfangen: " & strReciveValue, False)
Dim aryTextFile() As String = strReciveValue.Split(",")
lblMinVal.Text = aryTextFile(0)
intGrenzWert1 = CInt(aryTextFile(1)) - CInt(lblMinVal.Text)
intGrenzWert2 = CInt(aryTextFile(2)) - CInt(lblMinVal.Text)
GrenzwertShow(intGrenzWert1, intGrenzWert2)
ElseIf ((strReciveValue.Contains("#CO2-W,")) And (intDeviceFound = 1)) Then
strReciveValue = strReciveValue.Replace("#CO2-W,", "").Replace(";", "")
Dim arrRecValue() As String = strReciveValue.Split(",")
UpdateTxtStatus("CO2 Warngerät V1.1", False)
UpdateTxtStatus("CO2: " & arrRecValue(0) & " ppm / TVOC: " & arrRecValue(1) & " Volatile organic compounds", False)
UpdateTxtStatus("Temp: " & arrRecValue(2) & " °C / Feuchte: " & arrRecValue(3) & " %", False)
If cboChartTyp.SelectedIndex = 0 Then
UpdateAktValue(arrRecValue(0))
ChartValue.Visible = False
lbl10sek.Visible = False
Else
ChartValue.Visible = True
lbl10sek.Visible = True
End If
DrawChart(arrRecValue(0), arrRecValue(1), arrRecValue(2).Replace(".", ","), arrRecValue(3).Replace(".", ","), False, CInt(lblAktMin.Text), CInt(lblAktMax.Text))
End If
End Sub
#End Region
#Region "Status anpassen"
Private Sub UpdateTxtStatus(strText As String, bolClear As Boolean)
Static bolLocked As Boolean = False
If bolClear = False And bolLocked = False Then
lblStatus3.Text = lblStatus2.Text
lblStatus2.Text = lblStatus1.Text
lblStatus1.Text = strText
lblTimestamp3.Text = lblTimeStamp2.Text
lblTimeStamp2.Text = lblTimeStamp1.Text
lblTimeStamp1.Text = System.DateTime.Now.ToString()
ElseIf bolClear = True And bolLocked = False Then
lblStatus3.Text = ""
lblStatus2.ForeColor = Color.Red
lblStatus2.Text = strText
lblStatus1.Text = ""
bolLocked = True
lblTimestamp3.Text = ""
lblTimeStamp2.Text = System.DateTime.Now.ToString()
lblTimeStamp1.Text = ""
End If
End Sub
#End Region
#Region "Button Control"
Private Sub ButtonControl(intFunc As Integer, datacolor As Color)
If intFunc = 0 Then 'Nach Booten
cmdClose.Enabled = True
pnlGruen.Enabled = True
pnlRot.Enabled = True
lblMinVal.Enabled = True
lblMaxVal.Enabled = True
ElseIf intFunc = 1 Or intFunc = 2 Then
cmdplus.Enabled = True
cmdminus.Enabled = True
cmdFaktor.BackColor = datacolor
End If
If intFunc = 2 Then
lblMinVal.BackColor = datacolor
lblMaxVal.BackColor = datacolor
ElseIf intFunc = 3 Then
cmdplus.Enabled = False
cmdminus.Enabled = False
cmdSave.Enabled = False
cmdSaveCancel.Enabled = False
End If
End Sub
Private Sub ColorPanel_Click(sender As Object, e As EventArgs) Handles pnlRot.Click, pnlGruen.Click, pnlGelb.Click, lblMinVal.Click, lblMaxVal.Click
Select Case True
Case sender Is pnlRot Or sender Is pnlGruen
ButtonControl(2, Color.Gainsboro)
ButtonControl(1, (sender.backcolor))
Case sender Is lblMinVal Or sender Is lblMaxVal
ButtonControl(2, Color.Chocolate)
Case sender Is pnlGelb
ButtonControl(2, Color.Gainsboro)
ButtonControl(3, Color.Gainsboro)
End Select
End Sub
Private Sub PlusMinus_Click(sender As Object, e As EventArgs) Handles cmdplus.Click, cmdminus.Click
If cmdFaktor.BackColor = Color.Red Then
Select Case True
Case sender Is cmdplus
GrenzwertShow(intGrenzWert1, intGrenzWert2 + cmdFaktor.Text)
Case sender Is cmdminus
GrenzwertShow(intGrenzWert1, intGrenzWert2 - cmdFaktor.Text)
End Select
ElseIf cmdFaktor.backcolor = Color.Lime Then
Select Case True
Case sender Is cmdplus
GrenzwertShow(intGrenzWert1 + cmdFaktor.Text, intGrenzWert2)
Case sender Is cmdminus
GrenzwertShow(intGrenzWert1 - cmdFaktor.Text, intGrenzWert2)
End Select
ElseIf cmdFaktor.backcolor = Color.Chocolate Then
Select Case True
Case sender Is cmdplus
If lblMinVal.BackColor = Color.Chocolate Then
lblMinVal.Text = CInt(lblMinVal.Text) + CInt(cmdFaktor.Text)
End If
Case sender Is cmdminus
If ((lblMinVal.BackColor = Color.Chocolate) And (CInt(lblMinVal.Text) - CInt(cmdFaktor.Text) >= 300)) Then
lblMinVal.Text = CInt(lblMinVal.Text) - CInt(cmdFaktor.Text)
Else
UpdateTxtStatus("Grenzwert liegt ausserhalb des gültigen minimalen Bereiches!", False)
End If
End Select
End If
End Sub
Private Sub cmdFaktor_Click(sender As Object, e As EventArgs) Handles cmdFaktor.Click
If cmdFaktor.Text = 100 Then
cmdFaktor.Text = 1
Else
cmdFaktor.Text = cmdFaktor.Text * 10
End If
End Sub
Private Sub cmdSave_Change(sender As Object, e As EventArgs) Handles lblAktMax.TextChanged, lblAktMin.TextChanged, lblMaxVal.TextChanged
If cmdFaktor.BackColor <> Color.Gainsboro Then
cmdSave.Enabled = True
cmdSaveCancel.Enabled = True
End If
End Sub
Private Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click, cmdSaveCancel.Click
ButtonControl(2, Color.Gainsboro)
ButtonControl(3, Color.Gainsboro)
Select Case True
Case sender Is cmdSaveCancel
SerialPort.Write("#CO2-D;")
UpdateTxtStatus("Anfrage Grenzwerte...", False)
Case sender Is cmdSave
UpdateTxtStatus("Neue Grenzwerte werden übertragen...", False)
SerialPort.Write("#CO2-S," & lblMinVal.Text & "," & lblAktMin.Text & "," & lblAktMax.Text & ";")
UpdateTxtStatus("Empfange aktuelle Grenzwerte nach dem Speichern...", False)
SerialPort.Write("#CO2-D;")
End Select
End Sub
#End Region
#Region "Grenzwerte anpassen"
Private Sub GrenzwertShow(intGrenzeVal1 As Integer, intGrenzeVal2 As Integer)
If intGrenzeVal1 > 46 And intGrenzeVal1 < intGrenzeVal2 And intGrenzeVal2 < 854 Then
'Farben anpassen
pnlGruen.BackColor = Color.Lime
pnlGelb.BackColor = Color.Yellow
pnlRot.BackColor = Color.Red
'Anpassung Balken
pnlGruen.Location = New Point(0, pnlGruen.Location.Y)
pnlGruen.Width = intGrenzeVal1
pnlGelb.Location = New Point(intGrenzeVal1, pnlGelb.Location.Y)
pnlGelb.Width = 900 - intGrenzeVal1 - (900 - intGrenzeVal2)
pnlRot.Location = New Point(intGrenzeVal2, pnlRot.Location.Y)
pnlRot.Width = 900 - intGrenzeVal2
'Anpassung Variablen
intGrenzWert1 = intGrenzeVal1
intGrenzWert2 = intGrenzeVal2
'Anpassung Textfeld und Balken
pnlAktMin.Location = New Point(intGrenzeVal1 - 2, pnlAktMin.Location.Y)
pnlAktMax.Location = New Point(intGrenzeVal2 - 2, pnlAktMax.Location.Y)
lblAktMin.Location = New Point(intGrenzeVal1 - 42, lblAktMin.Location.Y)
lblAktMax.Location = New Point(intGrenzeVal2 + 2, lblAktMax.Location.Y)
'Werte anzeigen
ShowThreshold()
Else
UpdateTxtStatus("Grenzwert liegt ausserhalb des gültigen Bereich!", False)
End If
End Sub
Private Sub lblMinVal_TextChanged(sender As Object, e As EventArgs) Handles lblMinVal.TextChanged
If lblMinVal.Text <> "" Then
lblMaxVal.Text = CInt(lblMinVal.Text) + 900
ShowThreshold()
End If
End Sub
Private Sub ShowThreshold()
Dim intMaxSpace As Integer = CInt(pnlRot.Width) + CInt(pnlGelb.Width) + CInt(pnlGruen.Width)
Dim intAktSpace = CInt(lblMaxVal.Text) - CInt(lblMinVal.Text)
lblAktMin.Text = (intAktSpace * intGrenzWert1 / intMaxSpace) + CInt(lblMinVal.Text)
lblAktMax.Text = (intAktSpace * intGrenzWert2 / intMaxSpace) + CInt(lblMinVal.Text)
End Sub
Private Sub UpdateAktValue(intValue As Integer)
lblAktVal.Text = intValue
If ((intValue - CInt(lblMinVal.Text) - 26) <= 26) Then
lblAktVal.Location = New Point(1, lblAktVal.Location.Y)
panAktVal.Location = New Point(26, panAktVal.Location.Y)
lblAktVal.BackColor = Color.Lime
ElseIf ((intValue - CInt(lblMinVal.Text) - 26) >= 874) Then
lblAktVal.Location = New Point(847, lblAktVal.Location.Y)
panAktVal.Location = New Point(872, panAktVal.Location.Y)
lblAktVal.BackColor = Color.Red
Else
lblAktVal.Location = New Point(intValue - CInt(lblMinVal.Text) - 26, lblAktVal.Location.Y)
panAktVal.Location = New Point(intValue - CInt(lblMinVal.Text) - 2, panAktVal.Location.Y)
lblAktVal.BackColor = Color.White
End If
End Sub
#End Region
#Region "Chart anzeigen"
Public Sub DrawChart(sinCO2 As Single, sinTVOC As Single, sinTemp As Single, sinRF As Single, bolReset As Boolean, intMinGrenz As Integer, intMaxGrenz As Integer)
'Array Listen definieren
Static arrC02_10 As New List(Of Single)
Static arrC02_1000 As New List(Of Single)
Static arrTVOC_10 As New List(Of Single)
Static arrTVOC_1000 As New List(Of Single)
Static arrTemp_10 As New List(Of Single)
Static arrTemp_1000 As New List(Of Single)
Static arrRF_10 As New List(Of Single)
Static arrRF_1000 As New List(Of Single)
Static arrXVals As New List(Of Single)
Dim arrYVals As New List(Of Single)
'Weitere Variablen für Graphen
Dim arrGreen As New List(Of Integer) From {intMinGrenz, intMinGrenz}
Dim arrRed As New List(Of Integer) From {intMaxGrenz, intMaxGrenz}
Dim arr0to1000 As New List(Of Integer) From {0, 1000}
'Reset
If bolReset = True Then
arrC02_10.Clear()
arrC02_1000.Clear()
arrTVOC_10.Clear()
arrTVOC_1000.Clear()
arrTemp_10.Clear()
arrTemp_1000.Clear()
arrRF_10.Clear()
arrRF_1000.Clear()
arrXVals.Clear()
Exit Sub
End If
'Werte zwischenspeichern
arrC02_10.Add(sinCO2)
arrTVOC_10.Add(sinTVOC)
arrTemp_10.Add(sinTemp)
arrRF_10.Add(sinRF)
'Schreibe Werte für Graph
If arrC02_10.Count = 10 Or arrTVOC_10.Count = 10 Or arrTemp_10.Count = 10 Or arrRF_10.Count = 10 Then
arrC02_1000.Add(Math.Round(arrC02_10.Sum / 10, 0))
arrTVOC_1000.Add(Math.Round(arrTVOC_10.Sum / 10, 0))
arrTemp_1000.Add(Math.Round(arrTemp_10.Sum / 10, 2))
arrRF_1000.Add(Math.Round(arrRF_10.Sum / 10, 2))
arrC02_10.Clear()
arrTVOC_10.Clear()
arrTemp_10.Clear()
arrRF_10.Clear()
If arrXVals.Count < 1000 Then
arrXVals.Add(arrXVals.Count)
End If
If arrC02_1000.Count >= 2 Then
cboChartTyp.Enabled = True
cmdResetChart.Enabled = True
End If
End If
If arrC02_1000.Count > 1000 Or arrTVOC_1000.Count > 1000 Or arrTemp_1000.Count > 1000 Or arrRF_1000.Count > 1000 Then
arrC02_1000.RemoveAt(0)
arrTVOC_1000.RemoveAt(0)
arrTemp_1000.RemoveAt(0)
arrRF_1000.RemoveAt(0)
End If
'setup the chart
If cboChartTyp.SelectedIndex > 0 Then
With ChartValue.ChartAreas(0)
.AxisX.MajorGrid.LineColor = Color.LightBlue
.AxisY.MajorGrid.LineColor = Color.LightGray
End With
'X-Achse
Dim intXMax As Integer = RoundUpDown(arrXVals.Count - 1, 1)
Dim intXInterval As Integer = intXMax / 10
With ChartValue.ChartAreas(0)
.AxisX.Minimum = 0
.AxisX.Maximum = intXMax
.AxisX.Interval = intXInterval
End With
'y-Achse
Dim intYMin As Integer = 0
Dim intYmax As Integer = 0
Dim intYInterval As Integer = 0
If cboChartTyp.SelectedIndex = 1 Then 'CO2
intYMin = RoundUpDown(Math.Truncate(arrC02_1000.Min), -1)
intYmax = RoundUpDown(Math.Truncate(arrC02_1000.Max), 1)
intYInterval = (intYmax - intYMin) / 10
arrYVals = arrC02_1000
ElseIf cboChartTyp.SelectedIndex = 2 Then 'TVOC
intYMin = RoundUpDown(Math.Truncate(arrTVOC_1000.Min), -1)
intYmax = RoundUpDown(Math.Truncate(arrTVOC_1000.Max), 1)
intYInterval = (intYmax - intYMin) / 10
arrYVals = arrTVOC_1000
ElseIf cboChartTyp.SelectedIndex = 3 Then 'Temp
intYMin = RoundUpDown(Math.Truncate(arrTemp_1000.Min), -1)
intYmax = RoundUpDown(Math.Truncate(arrTemp_1000.Max), 1)
intYInterval = (intYmax - intYMin) / 10
arrYVals = arrTemp_1000
ElseIf cboChartTyp.SelectedIndex = 4 Then 'Feuchte
intYMin = RoundUpDown(Math.Truncate(arrRF_1000.Min), -1)
intYmax = RoundUpDown(Math.Truncate(arrRF_1000.Max), 1)
intYInterval = (intYmax - intYMin) / 10
arrYVals = arrRF_1000
End If
With ChartValue.ChartAreas(0)
.AxisY.Minimum = intYMin
.AxisY.Maximum = intYmax
.AxisY.Interval = intYInterval
End With
'Neues Diagramm
ChartValue.Series.Clear()
ChartValue.Series.Add("Value")
'Werte zeichen Blue
With ChartValue.Series(0)
.IsVisibleInLegend = False
.ChartType = DataVisualization.Charting.SeriesChartType.Line
.Color = Color.Blue
.BorderDashStyle = ChartDashStyle.Dash
.Points.DataBindXY(arrXVals, arrYVals)
End With
If cboChartTyp.SelectedIndex = 1 Then 'Nur bei C02 Wert
ChartValue.Series.Add("Min")
ChartValue.Series.Add("Max")
'Werte zeichen Green
With ChartValue.Series(1)
.IsVisibleInLegend = False
.ChartType = DataVisualization.Charting.SeriesChartType.Line
.Color = Color.Green
.BorderDashStyle = ChartDashStyle.Dash
.Points.DataBindXY(arr0to1000, arrGreen)
End With
'Werte zeichen Red
With ChartValue.Series(2)
.IsVisibleInLegend = False
.ChartType = DataVisualization.Charting.SeriesChartType.Line
.Color = Color.Red
.BorderDashStyle = ChartDashStyle.Dash
.Points.DataBindXY(arr0to1000, arrRed)
End With
End If
End If
End Sub
Private Sub cmdResetChart_Click(sender As Object, e As EventArgs) Handles cmdResetChart.Click
cboChartTyp.SelectedIndex = 0
DrawChart(0, 0, 0, 0, True, 0, 0)
cboChartTyp.Enabled = False
cmdResetChart.Enabled = False
End Sub
Function RoundUpDown(sinZahl As Single, intOffset As Single)
If ((Math.Round(sinZahl / 10, 0) <> sinZahl / 10) And (sinZahl > 0) And (intOffset < 0)) Then
intOffset = 0
ElseIf ((Math.Round(sinZahl / 10, 0) <> sinZahl / 10) And (sinZahl < 0) And (intOffset > 0)) Then
intOffset = 0
End If
sinZahl = Math.Truncate(sinZahl / 10)
sinZahl = sinZahl + intOffset
sinZahl = sinZahl * 10
Return sinZahl
End Function
#End Region
#Region "Form schließen"
Private Sub cmdClose_Click(sender As Object, e As EventArgs) Handles cmdClose.Click
If SerialPort.IsOpen Then
SerialPort.Write("#CO2-Exit;")
End If
UpdateTxtStatus("Verbindung wird getrennt und Anwendung geschlossen...", True)
intBootCount = 2
BootTimer.Enabled = True
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If intBootCount < 2 Then
e.Cancel = True
End If
End Sub
#End Region
End Class
Quellcode Arduino
Hier der Arduino Quellcode.
Der Quellcode wird durch das Einbinden in die Homepage automatisch angepasst. Es werden z. B. Zeilenumbrüche eingefügt.
Er kann somit nicht 1 zu 1 in die Arduino IDE übernommen werden.
Die Arduino IDE (IDE = Integrated Development Environment) ist eine Software zum Programmieren von Arduino-Mikrocontrollern. Sie ermöglicht es, Programme mit der Programmiersprache C oder C++ zu schreiben und auf die Arduino-Boards zu übertragen. Der Arduino-Mikrocontroller führt diese dann aus.
Im Download-Bereich könnt Ihr das Arduino-Projekt herunterladen und ggf. nach euren Wünschen anpassen und erweitern.
#include <EEPROM.h>
#include "Adafruit_CCS811.h"
Adafruit_CCS811 ccs;
#include <SHT21.h> // include SHT21 library
SHT21 sht;
int ledRot = 9;//6
int ledGelb = 10;//5
int ledGruen = 11;//4
long myTimer = 0;
long myTimeout = 1000;
int intConnectionOk = 0;
int arrGrenzValue[3] = { 0 };
int intCO2 = 0;
int intTVOC = 0;
float temp; // variable to store temperature
float humidity; // variable to store hemidity
void setup()
{
Serial.begin(115200); // opens serial port, sets data rate to 115200 bps
pinMode(ledRot, OUTPUT);
pinMode(ledGelb, OUTPUT);
pinMode(ledGruen, OUTPUT);
readEEprom(0);
/*C02 Sensor starten*/
if(!ccs.begin())
{
while(1){ShowLed (4);}//Failed to start sensor! Please check your wiring.
}
while(!ccs.available())// Wait for the sensor to be ready
{
ShowLed (1);
ShowLed (2);
ShowLed (3);
ShowLed (2);
}
/*Begin Wire(I2C) SHT21*/
Wire.begin();
}
void loop()
{
if (Serial.available()) serialEvent();
if (millis() > myTimeout + myTimer )
{
myTimer = millis();
/*Von Sensor lesen*/
if(ccs.available())
{
if(!ccs.readData())
{
intCO2 = ccs.geteCO2();
intTVOC = ccs.getTVOC();
}else
{
for (int i=0;i<2;i++)
{
ShowLed (4);
}
}
}
/*Von Sensor lesen*/
if (intConnectionOk == 0)
{
Serial.println ("#CO2-OK;");
}
else if (intConnectionOk == 1)
{
readEEprom(0);
Serial.println("#CO2-D," + String(arrGrenzValue[0],DEC) + "," + String(arrGrenzValue[1],DEC) + "," + String(arrGrenzValue[2],DEC) + ";");
intConnectionOk = 2;
}
else if (intConnectionOk == 2)
{
temp = sht.getTemperature(); // get temp from SHT
humidity = sht.getHumidity(); // get temp from SHT
Serial.println("#CO2-W," + String(intCO2,DEC) + "," + String(intTVOC,DEC) + "," + temp + "," + humidity + ";");
}
/*LEDS ansteuern*/
if (intCO2 >= arrGrenzValue[2])
{
ShowLed (3);//ROT
}else if ((intCO2 < arrGrenzValue[2])&&(intCO2 >= arrGrenzValue[1]))
{
ShowLed (2);//GELB
}else if (intCO2 < arrGrenzValue[1])
{
ShowLed (1);//Grün
}
/*LEDS ansteuern*/
}
}
/*//////String Abfrage\\\\\\*/
void serialEvent()
{
String strSerialReceive;
if (Serial.findUntil("#", ";"))
{
strSerialReceive = Serial.readStringUntil(';');//Grenzwerte auslesen Auslesen und senden.
if (strSerialReceive == "CO2-D")
{
myTimer = millis();
intConnectionOk = 1;
}
else if (strSerialReceive == "CO2-Exit")//Programm beenden und für neue Verbindung vorbereiten
{
myTimer = millis();
intConnectionOk = 0;
}
else if (strstr(strSerialReceive.c_str(), "CO2-S,") != NULL)//Neue Grenzwerte empfangen und Speichern im EE
{
myTimer = millis();
strSerialReceive.replace("CO2-S,","");
StrToInt (strSerialReceive);
ArrayToEEprom();
}
}
}
/*Led ansteuern*/
void ShowLed (int intLedSwitch)// 1 = Grün, 2 = Gelb, 3 = Rot, 4 = Rot 1mal blinken
{
static int intOldLed = 0;
int arrLedFromToOff[] = {0,0,0};
if (intLedSwitch < 4)
{
if (intOldLed == 0)
{
switch (intLedSwitch)
{
case 1:
analogWrite(ledGruen, 255);
break;
case 2:
analogWrite(ledGelb, 255);
break;
case 3:
analogWrite(ledRot, 255);
break;
}
intOldLed = intLedSwitch;
}
else
{
if (intOldLed != intLedSwitch)
{
if (intOldLed < intLedSwitch)
{
arrLedFromToOff[1] = intOldLed + 1;
}
if (intOldLed > intLedSwitch)
{
arrLedFromToOff[1] = intOldLed - 1;
}
arrLedFromToOff[0] = intOldLed;
intOldLed = arrLedFromToOff[1];
for (int intReadArr = 0 ; intReadArr <3; intReadArr++)
{
if (arrLedFromToOff[intReadArr]==1)
{
arrLedFromToOff[2]= 3;
break;
}else if (arrLedFromToOff[intReadArr]==3)
{
arrLedFromToOff[2]= 1;
break;
}
}
for (int intLedToArr = 0; intLedToArr < 3; intLedToArr++)
{
switch (arrLedFromToOff[intLedToArr])
{
case 1:
arrLedFromToOff[intLedToArr] = ledGruen;
break;
case 2:
arrLedFromToOff[intLedToArr] = ledGelb;
break;
case 3:
arrLedFromToOff[intLedToArr] = ledRot;
break;
}
}
int test;
for (int helligkeit =0; helligkeit <= 255; helligkeit = helligkeit +1)
{
analogWrite(arrLedFromToOff[2], 0);
analogWrite(arrLedFromToOff[0],255- helligkeit);
analogWrite(arrLedFromToOff[1], helligkeit);
delay (1);
test = helligkeit;
}
Serial.println(test);
}
}
}
else
{
analogWrite(ledGruen, 0);
analogWrite(ledGelb, 0);
analogWrite(ledRot, 255);
delay(100);
analogWrite(ledRot, 0);
delay(100);
}
}
/*Von EEProm lesen mit Startadresse*/
int readEEprom (int startadr)
{
int intEEAddOffset = 0;
for (int intReadLay = 0; intReadLay < 3; intReadLay++)
{
arrGrenzValue[intReadLay]=(EEPROM.read(intEEAddOffset)*1000)+(EEPROM.read(intEEAddOffset+1)*100)+(EEPROM.read(intEEAddOffset+2)*10)+(EEPROM.read(intEEAddOffset+3));
intEEAddOffset = intEEAddOffset + 4;
}
}
/*String in IntergerArray umwandeln*/
void StrToInt(String strValue)
{
char delimiter[] = ",";
char *ptr;
int i = 0;
char cstrValue[strValue.length() + 1];
strValue.toCharArray(cstrValue, strValue.length() + 1);
ptr = strtok(cstrValue, delimiter);
while (ptr != NULL)
{
arrGrenzValue[i] = atoi(ptr);
i++;
ptr = strtok(NULL, delimiter);
}
}
/*Array in EEprom Speichern wenn Werte unterschiedlich*/
void ArrayToEEprom()
{
int intEEAddOffset = 0;
byte arrSingelVal[4] = { 0 };
for (int intArrLay = 0; intArrLay < 3; intArrLay++)
{
arrSingelVal[0] = (arrGrenzValue[intArrLay] / 1000) % 10;
arrSingelVal[1] = (arrGrenzValue[intArrLay] / 100) % 10;
arrSingelVal[2] = (arrGrenzValue[intArrLay] / 10) % 10;
arrSingelVal[3] = arrGrenzValue[intArrLay] % 10;
for (int intSingelVal = 0; intSingelVal < 4; intSingelVal++)
{
if (EEPROM.read(intEEAddOffset) != arrSingelVal[intSingelVal])
{
EEPROM.write(intEEAddOffset, arrSingelVal[intSingelVal]);
}
intEEAddOffset ++;
}
}
}
Download
Die App sowie das Arduino Projekt könnt Ihr direkt von unserer Seite downloaden. Euch steht natürlich frei, die ganzen Elemente nach euren Interessen anzupassen.
Bitte Datenschutzerklärung beachten!
Vor, während und nach dem Spielen, werden Daten mit unserem Server ausgetauscht. In unserer Datenschutzerklärung erhaltet Ihr hierzu weitere Informationen.