diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/update_database.nim | 75 | ||||
| -rw-r--r-- | src/update_graphs.nim | 107 |
2 files changed, 182 insertions, 0 deletions
diff --git a/src/update_database.nim b/src/update_database.nim new file mode 100644 index 0000000..1a27517 --- /dev/null +++ b/src/update_database.nim @@ -0,0 +1,75 @@ +import json +import os +import osproc +import parsecfg +import strformat +import strutils + +type + CgiError = object of CatchableError + code: int + +proc newCgiError(code: int, message: string): ref CgiError = + result = newException(CgiError, message) + result.code = code + +proc readData(): string = + var size = parseInt(getEnv("CONTENT_LENGTH").string) + if size == 0: + return "" + result = newString(size) + if readBuffer(stdin, addr result[0], size) != 0: + raise newCgiError(400, "not enough data") + +proc main() = + if paramCount() != 2: + raise newCgiError(500, "one argument required") + + let config = loadConfig(paramStr(1)) + let databaseDir = config.getSectionValue("", "databaseDir") + if databaseDir == "": + raise newCgiError(500, "databaseDir is empty") + + if getEnv("REQUEST_METHOD") != "POST": + raise newCgiError(400, "request method must be POST") + + let j = parseJson(readData()) + + for alias, measurement in j: + let filename = normalizedPath(joinPath(databaseDir, alias & ".rrd")) + + if not filename.startsWith(databaseDir): + raise newCgiError(400, "invalid database") + let + timestamp = measurement["timestamp"].getBiggestInt() + temperature = measurement["temperature"].getFloat() + humidity = measurement["humidity"].getFloat() + pressure = measurement["pressure"].getFloat() + battery = measurement["battery_potential"].getFloat() + data = &"{timestamp}:{temperature}:{humidity}:{pressure}:{battery}" + (_, ec) = execCmdEx(&"rrdtool update {filename} {data}") + if ec != 0: + raise newCgiError(500, "rrdtool failed") + +try: + main() + echo("Content-Type: text/plain") + echo("") +except CgiError as e: + echo(&"Status: {e.code}") + echo("Content-Type: text/plain") + echo("") + echo(e.msg) + quit(0) +except JsonParsingError as e: + echo(&"Status: 400 Bad Request") + echo("Content-Type: text/plain") + echo("") + echo(&"invalid json: {e.msg}") + quit(0) +except Exception as e: + echo(&"Status: 500 Internal Server Error") + echo("Content-Type: text/plain") + echo("") + echo(e.msg) + quit(0) diff --git a/src/update_graphs.nim b/src/update_graphs.nim new file mode 100644 index 0000000..3f902a4 --- /dev/null +++ b/src/update_graphs.nim @@ -0,0 +1,107 @@ +import os +import osproc +import strformat + +let + databaseDir = getAppDir().parentDir() / "database" + outputDir = paramStr(2) + width = 800 + height = 600 + +proc graph(filename, title, vlabel: string, args: varargs[string, `$`]) = + var cmdline: seq[string] = @[ + "graph", joinPath(outputDir, filename), + "--width", $width, + "--height", $height, + "--title", title, + "--vertical-label", vlabel, + ] & @args + + echo(&"Generating {joinPath(outputDir, filename)} ...") + + let p = startProcess("rrdtool", args=cmdline, + options={poStdErrToStdOut, poUsePath, poParentStreams}) + + if p.waitForExit() != 0: + quit(1) + + +for database in walkFiles(joinPath(databaseDir, "*.rrd")): + let (_, base, _) = splitFile(database) + + graph(&"{base}-temperature-today.png", "Temperature", "Celcius", + "--end", "23:59 today", + "--start", "00:00 today", + "--alt-autoscale", + "--left-axis-format", "%.1lf", + &"DEF:temp1={database}:temperature:AVERAGE", + &"DEF:temp2={database}:temperature:AVERAGE:end=00\\:00 today:start=end-24h", + "LINE1:temp1#000000:today", + "LINE1:temp2#FF0000:yesterday", + "SHIFT:temp2:86400", + ) + + graph(&"{base}-temperature-month.png", "Temperature", "Celcius", + "--end", "23:59 today", + "--start", "end-1month", + "--step", "86400", + "--alt-autoscale", + "--x-grid", "DAY:1:DAY:1:DAY:1:86400:%d", + &"DEF:avg={database}:temperature:AVERAGE", + &"DEF:min={database}:temperature:MIN", + &"DEF:max={database}:temperature:MAX", + "LINE1:avg#000000:average", + "LINE2:min#FF0000:min", + "LINE3:max#00FF00:max" + ) + + graph(&"{base}-humidity-today.png", "Relative humidity", "%", + "--end", "23:59 today", + "--start", "00:00 today", + &"DEF:humi1={database}:humidity:AVERAGE", + &"DEF:humi2={database}:humidity:AVERAGE:end=00\\:00 today:start=end-24h", + "LINE1:humi1#000000:today", + "LINE1:humi2#FF0000:yesterday", + "SHIFT:humi2:86400", + ) + + graph(&"{base}-humidity-month.png", "Relative humidity", "%", + "--end", "23:59 today", + "--start", "end-1month", + "--step", "86400", + "--alt-autoscale", + "--x-grid", "DAY:1:DAY:1:DAY:1:86400:%d", + &"DEF:avg={database}:humidity:AVERAGE", + &"DEF:min={database}:humidity:MIN", + &"DEF:max={database}:humidity:MAX", + "LINE1:avg#000000:average", + "LINE2:min#FF0000:min", + "LINE3:max#00FF00:max", + ) + + graph(&"{base}-pressure-today.png", "Pressure", "Pascal", + "--end", "23:59 today", + "--start", "00:00 today", + "--alt-autoscale", + "--left-axis-format", "%.1lf", + &"DEF:pres1={database}:pressure:AVERAGE", + &"DEF:pres2={database}:pressure:AVERAGE:end=00\\:00 today:start=end-24h", + "LINE1:pres1#000000:today", + "LINE1:pres2#FF0000:yesterday", + "SHIFT:pres2:86400", + ) + + graph(&"{base}-pressure-month.png", "Pressure", "Pascal", + "--end", "23:59 today", + "--start", "end-1month", + "--step", "86400", + "--alt-autoscale", + "--x-grid", "DAY:1:DAY:1:DAY:1:86400:%d", + "--left-axis-format", "%.1lf", + &"DEF:avg={database}:pressure:AVERAGE", + &"DEF:min={database}:pressure:MIN", + &"DEF:max={database}:pressure:MAX", + "LINE1:avg#000000:average", + "LINE2:min#FF0000:min", + "LINE3:max#00FF00:max", + ) |
