-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgardend.lua
111 lines (87 loc) · 3.2 KB
/
gardend.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
local state = require('state')
local periphery = require('periphery')
-- Version constant
GARDEND_VERSION = "1.0.1"
-- Usage
if #arg < 1 then
io.stderr:write(string.format('Usage: %s %s <configuration file>\n\n', arg[-1], arg[0]))
io.stderr:write(string.format('gardend version %s\n', GARDEND_VERSION))
os.exit(-1)
end
-- Load configuration
local function loadconfig(path)
local f = assert(io.open(path, 'r'))
local t = f:read('*all')
f:close()
local env = {}
load(t, nil, 't', env)()
if env.configuration == nil then
error("Invalid configuration: 'configuration' table missing.")
end
return env.configuration
end
local ok, gardenConfig = pcall(loadconfig, arg[1])
if not ok then
io.stderr:write(tostring(gardenConfig) .. "\n")
os.exit(-1)
end
-- Open Log file
if gardenConfig.logfile == nil then
logfile = io.stdout
else
logfile = assert(io.open(gardenConfig.logfile, "a"))
end
function log(fmt, ...)
logfile:write(os.date("[%c] ") .. string.format(fmt, unpack({...})) .. "\n")
logfile:flush()
end
-- Load blocks
local function loadblocks(configuration)
local blkobjects = {}
-- Allow loading foo/bar/init.lua with foo.bar
package.path = package.path .. ";./?/init.lua"
for _, blktype in ipairs({"inputs", "controllers", "outputs", "postprocessors"}) do
if configuration[blktype] == nil then
error("Invalid configuration: missing '" .. blktype .. "' subtable.")
end
for blkinstance, blkconfig in pairs(configuration[blktype]) do
if blkconfig.driver == nil then
error("Invalid configuration: instance '" .. blkinstance .. "' missing 'driver' in configuration")
end
local blkpath = blktype .. "." .. blkconfig.driver
log("Loading %s block '%s' (%s)", blktype, blkinstance, blkpath)
local ok, object = pcall(require(blkpath), blkconfig)
if not ok then
error(string.format("configuring block '%s' (%s): %s", blkinstance, blkpath, tostring(object)))
end
blkobjects[#blkobjects+1] = {instance = blkinstance, type = blktype, path = blkpath, object = object}
end
end
return blkobjects
end
local ok, gardenBlocks = pcall(loadblocks, gardenConfig)
if not ok then
io.stderr:write(tostring(gardenBlocks) .. "\n")
os.exit(-1)
end
-- Create state structure
local gardenState = state.new(gardenConfig.dbfile)
-- Setup a few system constants
GARDEND_CONFIG_NAME = gardenConfig.name
GARDEND_TIMESTEP = gardenConfig.timestep
GARDEND_START_TIME = os.time()
-- Run system loop
while true do
local timestamp = gardenState:stamp()
for _, block in ipairs(gardenBlocks) do
log("Processing %s block instance '%s' (%s)", block.type, block.instance, block.path)
local ok, err = pcall(function () block.object:process(gardenState) end)
if not ok then
log("Error processing %s block instance '%s' (%s): %s", block.type, block.instance, block.path, tostring(err))
end
end
log("Recording state...")
gardenState:record()
log("Sleeping...")
periphery.sleep_ms(math.max((timestamp + gardenConfig.timestep - os.time())*1000, 0.0))
end