Microsoft Small Basic

Program Listing: PVXC450.000-1
' Environment Meter
' Version 0.3.0
' Copyright © 2021 Nonki Takahashi. The MIT License.
' Last update 2021-05-14
' Program ID PVXC450.000-1

title = "Environment Meter"
GraphicsWindow.Title = title
debug = "False"
Init()
path = Program.Directory + "\EnvironmentMeter.log"
While "True"
GetLine()
If line <> "" Then
rec = ""
param = LDText.Split(line, ",")
rec["year"] = Clock.Year
rec["month"] = Clock.Month
rec["day"] = Clock.Day
rec["hour"] = Clock.Hour
rec["min"] = Clock.Minute
rec["sec"] = Clock.Second
c = param[1] ' [ppm]
rec["co2"] = c
t = param[2] ' [℃]
rec["temp"] = t
rh = LDText.Replace(param[3], " ", "") ' [%]
rec["rh"] = rh
GetWBGT() ' w [℃]
Shapes.SetText(tmp, w + "℃")
If (-30 < t) And (t < 50) Then
Shapes.SetText(txt, (t * 1) + "℃")
DrawTemp()
' saturated water vapor pressure [hPa]
e = 6.1078 * Math.Power(10, 7.5 * t / (t + 237.3))
' saturated water vapor density [g/m^3]
a = 216.7 * e / (t + 273.15)
EndIf
Shapes.SetText(co2, c + "ppm")
If c < 400 Then
hue = 120
ElseIf 1000 < c Then
hue = 0
Else
hue = (1000 - c) * 120 / 600
EndIf
rc = LDColours.HSLtoRGB(hue, 1, 0.5)
LDShapes.PenColour(co2ring, rc)
If (0 <= rh) And (rh <= 100) Then
' volumetric humidity [g/m^3]
vh = Math.Round(a * rh / 100)
Shapes.SetText(vhTxt, vh)
vw = LDShapes.Width(vhTxt)
Shapes.Move(vhTxt, 2 * tw + hw - 55 - vw, 10)
Shapes.SetText(hum, rh + "%")
_a = rh * 180 / 100
LDShapes.RotateAbout(pointer, cx, cy, _a)
EndIf
date = rec["year"] + "/" + rec["month"] + "/" + rec["day"]
time = rec["hour"] + ":" + rec["min"] + ":" + rec["sec"]
GraphicsWindow.Title = title + " | " + date + " " + time
If (c < 5000) And (_min <> rec["min"]) And (rh <= 100) Then
' The following line could be harmful and has been automatically commented.
' File.AppendContents(path, rec)
UpdateGraph()
_min = rec["min"]
EndIf
EndIf
Program.Delay(200)
EndWhile

Sub DrawTemp
If temp <> "" Then
Shapes.Remove(temp)
EndIf
GraphicsWindow.BrushColor = "#DD0000"
GraphicsWindow.PenWidth = 0
temp = Shapes.AddRectangle(4, (t + 30) * 4.5)
Shapes.Move(temp, tw / 2 - 2, y1 + (50 - t) * 4.5)
EndSub

Sub GetLine
len = Text.GetLength(buf)
If p <= len Then
line = Text.GetSubText(buf, p, len - p + 1)
nl = Text.GetIndexOf(line, CRLF)
If 0 < nl Then
line = Text.GetSubText(line, 1, nl - 1)
p = p + nl + 1
Else
line = ""
EndIf
Else
line = ""
EndIf
EndSub

Sub GetWBGT
' param t - temperature [℃]
' param rh - relative humidity [%]
' return w - WBGT [℃]
If (21 <= t) And (t <= 40) And (20 <= rh) And (rh <= 100) Then
rem = Math.Remainder(h, 5)
If rem = 0 Then
w = wbgt[t][h]
Else
h1 = h - rem
h2 = h1 + 5
w1 = wbgt[t][h1]
w2 = wbgt[t][h2]
w = Math.Round(w1 + (w2 - w1) / (h2 - h1) * (h - h1))
EndIf
Else
w = "N/A"
EndIf
EndSub

Sub Init
CRLF = Text.GetCharacter(13) + Text.GetCharacter(10)
InitWBGT()
gw = 800
tw = 200
gh = 600
GraphicsWindow.Width = gw
GraphicsWindow.Height = gh
GraphicsWindow.Top = 20
GraphicsWindow.Left = 20
bg = "#333333"
GraphicsWindow.BackgroundColor = bg
' CO2 meter
GraphicsWindow.PenColor = "Lime"
GraphicsWindow.PenWidth = 10
GraphicsWindow.BrushColor = "Transparent"
co2ring = Shapes.AddEllipse(tw, tw)
Shapes.Move(co2ring, tw, 10)
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontName = "Trebuchet MS"
GraphicsWindow.FontSize = 40
co2 = Shapes.AddText("0000ppm")
Shapes.Move(co2, tw + 15, tw / 2 - 15)
' humidity meter
GraphicsWindow.BrushColor = "#EEFFFF"
hx = 2 * tw + 10
hy = 10
hw = gw - 2 * tw - 20
hh = tw
GraphicsWindow.FillRectangle(hx, hy, hw, hh)
GraphicsWindow.PenWidth = 2
GraphicsWindow.BrushColor = "Gray"
hum = Shapes.AddText("50%")
Shapes.Move(hum, 2 * tw + 20, 10)
vhTxt = Shapes.AddText("?")
vw = LDShapes.Width(vhTxt)
Shapes.Move(vhTxt, 2 * tw + hw - 55 - vw, 10)
GraphicsWindow.FontSize = 30
GraphicsWindow.DrawText(2 * tw + hw - 55, 20, "g/㎥")
pc = "#111166"
GraphicsWindow.BrushColor = pc
cs = 20
cx = hx + hw / 2
cy = hy + hh - cs
GraphicsWindow.FillEllipse(cx - cs / 2, cy - cs / 2, cs, cs)
pl = 100
GraphicsWindow.PenColor = "Gray"
r1 = 1.02
r3 = 1.4
r4 = 0.98
r5 = 0.7
as = pl * r4
at = pl * (r4 - r5) / 2
GraphicsWindow.BrushColor = "Gray"
GraphicsWindow.PenWidth = 2
GraphicsWindow.FontSize = 20
i = 0
For h = 0 To 100 Step 2
a = h * 180 / 100
_a = Math.GetRadians(a)
If Math.Remainder(h, 10) = 0 Then
x3 = cx - r3 * pl * Math.Cos(_a)
y3 = cy - r3 * pl * Math.Sin(_a)
GraphicsWindow.DrawText(x3 - 10, y3 - 12, h)
r2 = 1.2
Else
r2 = 1.1
EndIf
i = i + 1
x4[i] = cx - r4 * pl * Math.Cos(_a)
y4[i] = cy - r4 * pl * Math.Sin(_a)
x5[i] = cx - r5 * pl * Math.Cos(_a)
y5[i] = cy - r5 * pl * Math.Sin(_a)
x1 = cx - r1 * pl * Math.Cos(_a)
y1 = cy - r1 * pl * Math.Sin(_a)
x2 = cx - r2 * pl * Math.Cos(_a)
y2 = cy - r2 * pl * Math.Sin(_a)
GraphicsWindow.DrawLine(x1, y1, x2, y2)
EndFor
GraphicsWindow.PenWidth = 0
dry = LDColours.HSLtoRGB(55, 1, 0.65)
GraphicsWindow.BrushColor = dry
For i = 1 To 21
points[i][1] = x4[i]
points[i][2] = y4[i]
EndFor
For i = 21 To 1 Step -1
points[43 - i][1] = x5[i]
points[43 - i][2] = y5[i]
EndFor
LDShapes.AddPolygon(points)
GraphicsWindow.BrushColor = "Lime"
points = ""
For i = 21 To 31
points[i - 20][1] = x4[i]
points[i - 20][2] = y4[i]
EndFor
For i = 31 To 21 Step -1
points[43 - i][1] = x5[i]
points[43 - i][2] = y5[i]
EndFor
LDShapes.AddPolygon(points)
wet = LDColours.HSLtoRGB(185, 1, 0.35)
GraphicsWindow.BrushColor = wet
points = ""
For i = 31 To 51
points[i - 30][1] = x4[i]
points[i - 30][2] = y4[i]
EndFor
For i = 51 To 31 Step -1
points[73 - i][1] = x5[i]
points[73 - i][2] = y5[i]
EndFor
LDShapes.AddPolygon(points)
GraphicsWindow.PenWidth = 2
GraphicsWindow.PenColor = pc
pointer = Shapes.AddLine(cx, cy, cx - pl, cy)
LDShapes.RotateAbout(pointer, cx, cy, 90)
' thermometer
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(10, 10, tw - 20, gh - 20)
GraphicsWindow.BrushColor = "Gray"
GraphicsWindow.FontSize = 40
txt = Shapes.AddText("")
Shapes.Move(txt, 20, 10)
GraphicsWindow.FontSize = 20
GraphicsWindow.DrawText(20, 50, "WBGT")
GraphicsWindow.FontSize = 30
tmp = Shapes.AddText("")
Shapes.Move(tmp, 20, 70)
GraphicsWindow.FontSize = 40
y1 = 138
y2 = gh - 100
t = 50
GraphicsWindow.PenColor = "Gray"
For y = y1 To y2 Step 9
If Math.Remainder(y, 45) = 3 Then
x1 = tw / 2 - 40
x2 = tw / 2 + 40
If t < 0 Then
GraphicsWindow.DrawText(tw / 2 - 82, y - 40, t)
Else
GraphicsWindow.DrawText(tw / 2 + 20, y - 40, t)
EndIf
t = t - 10
Else
x1 = tw / 2 - 20
x2 = tw / 2 + 20
EndIf
GraphicsWindow.DrawLine(x1, y, x2, y)
EndFor
GraphicsWindow.BrushColor = "LightGray"
GraphicsWindow.FillEllipse(tw / 2 - 15, gh - 60, 30, 30)
GraphicsWindow.FillEllipse(tw / 2 - 5, 60, 10, 10)
GraphicsWindow.FillRectangle(tw / 2 - 5, 65, 10, gh - 100)
GraphicsWindow.BrushColor = "#DD0000"
GraphicsWindow.FillEllipse(tw / 2 - 10, gh - 55, 20, 20)
GraphicsWindow.FillRectangle(tw / 2 - 2, gh - 102, 4, 50)
' graph
xx = tw
xy = hy + hh + 10
xw = gw - tw - 10
xh = gh - hh - 30
GraphicsWindow.BrushColor = "#444444"
GraphicsWindow.FillRectangle(xx, xy, xw, xh)
xx0 = xx + 70
xx1 = xx + xw - 40
xy0 = xy + xh - 30
xy1 = xy + 20
dxx = Math.Floor((xx1 - xx0) / 20)
dxy = Math.Floor((xy1 - xy0) / 10)
GraphicsWindow.PenColor = "#666666"
GraphicsWindow.BrushColor = "#666666"
sec = -600
GraphicsWindow.FontSize = 14
For xx_ = xx0 To xx1 Step dxx
GraphicsWindow.DrawLine(xx_, xy0, xx_, xy1)
If Math.Remainder(sec, 60) = 0 Then
If sec = 0 Then
min = "0min"
Else
min = sec / 60
EndIf
GraphicsWindow.DrawText(xx_ - 7, xy0 + 5, min)
EndIf
sec = sec + 30
EndFor
v0[1] = -50
t = v0[1]
v0[2] = 300
c = v0[2]
v0[3] = 0
rh = v0[3]
gc[1] = "#FF3333"
gc[2] = "#00CC00"
gc[3] = "#3333FF"
key[1] = "temp"
key[2] = "co2"
key[3] = "rh"
For xy_ = xy0 To xy1 Step dxy
GraphicsWindow.DrawLine(xx0, xy_, xx1, xy_)
GraphicsWindow.BrushColor = gc[1]
GraphicsWindow.DrawText(xx + 5, xy_ - 10, t)
t = t + 10
GraphicsWindow.BrushColor = gc[2]
GraphicsWindow.DrawText(xx + 30, xy_ - 10, c)
c = c + 100
GraphicsWindow.BrushColor = gc[3]
GraphicsWindow.DrawText(xx1 + 5, xy_ - 10, rh)
rh = rh + 10
EndFor
v1[1] = t - 10
v1[2] = c - 100
v1[3] = rh - 10
p = 1 ' COM3 receive buffer pointer
status = LDCommPort.OpenPort("COM4", 115200)
If status <> "SUCCESS" Then
TextWindow.WriteLine("status=" + status)
EndIf
LDCommPort.SetEncoding("Ascii")
LDCommPort.DataReceived = OnDataReceived
EndSub

Sub InitWBGT
_wbgt[40] = "29,30,31,32,33,34,35,35,36,37,38,39,40,41,42,43,44"
_wbgt[39] = "28,29,30,31,32,33,34,35,35,36,37,38,39,40,41,42,43"
_wbgt[38] = "28,28,29,30,31,32,33,34,35,35,36,37,38,39,40,41,42"
_wbgt[37] = "27,28,29,29,30,31,32,33,33,35,35,36,37,38,39,40,41"
_wbgt[36] = "26,27,28,29,29,30,31,32,33,34,34,35,36,37,38,39,39"
_wbgt[35] = "25,26,27,28,29,29,30,31,32,33,33,34,35,36,37,38,38"
_wbgt[34] = "25,25,26,27,28,29,29,30,31,32,33,33,34,35,36,37,37"
_wbgt[33] = "24,25,25,26,27,28,28,29,30,31,32,32,33,34,35,35,36"
_wbgt[32] = "23,24,25,25,26,27,28,28,29,30,31,31,32,33,34,34,35"
_wbgt[31] = "22,23,24,24,25,26,27,27,28,29,30,30,31,32,33,33,34"
_wbgt[30] = "21,22,23,24,24,25,26,27,27,28,29,29,30,31,32,32,33"
_wbgt[29] = "21,21,22,23,24,24,25,26,26,27,28,29,29,30,31,31,32"
_wbgt[28] = "20,21,21,22,23,23,24,25,25,26,27,28,28,29,30,30,31"
_wbgt[27] = "19,20,21,21,22,23,23,24,25,25,26,27,27,28,29,29,30"
_wbgt[26] = "18,19,20,20,21,22,22,23,24,24,25,26,26,27,28,28,29"
_wbgt[25] = "18,18,19,20,20,21,22,22,23,23,24,25,25,26,27,27,28"
_wbgt[24] = "17,18,18,19,19,20,21,21,22,22,23,24,24,25,26,26,27"
_wbgt[23] = "16,17,17,18,18,19,19,20,21,22,22,23,23,24,25,25,26"
_wbgt[22] = "15,16,17,17,18,18,19,19,20,21,21,22,22,23,24,24,25"
_wbgt[21] = "15,15,16,16,17,17,18,19,19,20,20,21,21,22,23,23,24"
For t = 40 To 21 Step -1
w = LDText.Split(_wbgt[t], ",")
i = 1
For rh = 20 To 100 Step 5
wbgt[t][rh] = w[i]
i = i + 1
EndFor
EndFor
EndSub

Sub OnDataReceived
buf = Text.Append(buf, LDCommPort.RXAll())
EndSub

Sub UpdateGraph
' param rec - current record
n = n + 1
If debug Then
TextWindow.WriteLine("n = " + n)
EndIf
GraphicsWindow.PenWidth = 2
' remove graph
If 11 < n Then
For g = 1 To 3
Shapes.Remove(l[n - 11][g])
If debug Then
TextWindow.WriteLine("- l[" + (n - 11) + "]")
EndIf
l[n - 11][g] = ""
log[n - 11][g] = ""
EndFor
EndIf
' move graph
If 2 < n Then
m = Math.Max(1, n - 10)
If debug Then
TextWindow.WriteLine("m = " + m)
EndIf
For i = m To n - 2
For g = 1 To 3
_x1 = xx1 - (xx1 - xx0) * (n - i) / 10
_y1 = log[i][g]
_x2 = xx1 - (xx1 - xx0) * (n - i - 1) / 10
_y2 = log[i + 1][g]
LDShapes.MoveLine(l[i][g], _x1, _y1, _x2, _y2)
If debug Then
TextWindow.WriteLine("< l[" + i + "][" + g + "] = (" + _x1 + "," + _y1 + "," + _x2 + "," + _y2 + ")")
EndIf
EndFor
EndFor
EndIf
' add graph
For g = 1 To 3
value = rec[key[g]]
Value2Y()
log[n][g] = xy
If debug Then
TextWindow.WriteLine("log[" + n + "][" + g + "] = " + xy)
EndIf
EndFor
If 1 < n Then
For g = 1 To 3
GraphicsWindow.PenColor = gc[g]
_x1 = xx1 - (xx1 - xx0) / 10
_y1 = log[n - 1][g]
_x2 = xx1
_y2 = log[n][g]
l[n - 1][g] = Shapes.AddLine(_x1, _y1, _x2, _y2)
If debug Then
TextWindow.WriteLine("+ l[" + (n - 1) + "][" + g + "] = (" + _x1 + "," + _y1 + "," + _x2 + "," + _y2 + ")")
EndIf
EndFor
EndIf
EndSub

Sub Value2Y
' param value
' param g - 1 if temp, 2 if co2, 3 if rh
' return xy
xy = xy0 - (xy0 - xy1) * (value - v0[g]) / (v1[g] - v0[g])
EndSub