s-youless.mkiv /size: 10 Kb    last modification: 2020-07-01 14:35
1%D \module
2%D   [      file=s-youless,
3%D        version=2013.11.12,
4%D          title=\CONTEXT\ Style File,
5%D       subtitle=Youless Graphics,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14%D This is experimental code. When I have collected enough data I will make the
15%D graphics nicer and provide some more.
16%D
17%D The Jouless can serve web pages but there is not much detail in them. They also are
18%D somewhat bad \HTML, like unquoted attributes and so. We don't need this anyway as we
19%D can also fetch data directly. The data is collected using a dedicated helper script
20%D (of course we could just call it as module too). The data is fetched from the Jouless
21%D device using queries (currently we use json, but a more direct parsing of data might
22%D be more efficient). The data is converted into a proper \LUA\ table and saved (merged).
23
24% in cronjob on one of the servers:
25%
26% mtxrun --script youless --collect --host=192.168.2.50 --nobackup --electricity youless-electricity.lua
27
28\startluacode
29
30    require("util-you")
31
32    local round = math.round
33
34    moduledata.youless = { }
35
36    local defaults = {
37        electricity = {
38            unit    = "watt",
39            maxunit = "maxwatt",
40        },
41        watt        = {
42            unit    = "watt",
43            maxunit = "maxwatt",
44        },
45        pulse       = {
46            unit    = "watt",
47            maxunit = "maxwatt",
48        },
49        gas         = {
50            unit    = "liters",
51            maxunit = "maxliters",
52        },
53    }
54
55    local function process(specification,thevariant)
56
57        local data, message = utilities.youless.analyze(specification.filename or "youless-electricity.lua")
58
59        if not data then
60            context(message)
61            return
62        end
63
64        local variant = data.variant
65        local unit    = specification.unit
66        local maxunit = specification.maxunit
67
68        if thevariant then
69            if variant ~= thevariant then
70                context("invalid variant")
71                return
72            end
73        elseif variant then
74            local d = defaults[variant]
75            if d then
76                unit    = d.unit
77                maxunit = d.maxunit
78            else
79                context("unknown variant")
80                return
81            end
82        else
83            context("invalid variant")
84            return
85        end
86
87        local year    = tonumber(specification.year) or os.today().year
88        local month   = tonumber(specification.month)
89        local years   = data.years
90        local max     = specification[maxunit]
91
92        if not max then
93            if unit == "watt" then
94                max = 10000
95            elseif unit == "liters" then
96                max = 1000
97            else
98                max = 5000 -- can't happen
99            end
100        end
101
102        local firstmonth = month or 1
103        local lastmonth  = month or 12
104
105        local max   = max
106        local delta = round(max/10)
107        local scale = round(delta/20)
108        local mark  = 3
109
110        for y=year,year do
111            local year = years[y]
112            if year then
113                local grand = 0
114                for m=firstmonth,lastmonth do
115                    local month = year.months[m]
116                    if month then
117                        context.startMPpage { offset = "10pt" }
118                        context("linecap := butt; pickup pencircle scaled .5")
119
120                        for i=0,(math.div(max,delta)+1)*delta,delta/10 do
121                            context("draw (%s,%s) -- (%s,%s) withcolor .6white ;",0,i/scale,31 * 24,i/scale)
122                        end
123
124                        context("draw (0,%s) -- (31 * 24,%s) dashed dashpattern(on 6 off 6) withcolor darkgreen withpen pencircle scaled 1 ;",year [unit]/scale,year [unit]/scale)
125                        context("draw (0,%s) -- (31 * 24,%s) dashed dashpattern(off 6 on 6) withcolor darkred   withpen pencircle scaled 1 ;",month[unit]/scale,month[unit]/scale)
126
127                        local days  = month.days
128                        local total = 0
129                        if days then
130                            local nd = os.nofdays(y,m)
131                            for d=1,nd do
132                                local day     = days[d]
133                                local xoffset = (d-1) * 24
134                                local wd      = os.weekday(d,m,y)
135                                local weekend = wd == 1 or wd == 7
136                                if not weekend then
137                                    -- okay
138                                elseif mark == 1 then
139                                    context("draw (%s,%s) -- (%s,%s) ; ",xoffset,   -17.5,xoffset,   -32.5)
140                                    context("draw (%s,%s) -- (%s,%s) ; ",xoffset+24,-17.5,xoffset+24,-32.5)
141                                elseif mark == 2 then
142                                    context("draw (%s,%s) -- (%s,%s) ;",xoffset,    -17.5,xoffset+24,-17.5)
143                                    context("draw (%s,%s) -- (%s,%s) ;",xoffset,    -32.5,xoffset+24,-32.5)
144                                elseif mark == 3 then
145                                    context("draw unitsquare xysized (%s,%s) shifted (%s,%s) ;",24,15,xoffset,-32.5)
146                                end
147                                context([[draw textext("\strut%s") shifted (%s,%s) ;]],d,xoffset + 12,-25)
148                                if day then
149                                    for h=0,23 do
150                                        local hours = day.hours
151                                        if hours then
152                                            local hour = hours[h]
153                                            if hour then
154                                                local dx = xoffset + h
155                                                local dy = hour[unit]/scale
156                                                local dm = hour[maxunit]/scale
157                                                context("draw (%s,%s) -- (%s,%s) withcolor %s ;",dx, 0,dx,dy,weekend and "darkmagenta" or "darkblue")
158                                                context("draw (%s,%s) -- (%s,%s) withcolor %s ;",dx,dy,dx,dm,"darkgray")
159                                            end
160                                        end
161                                    end
162                                    local use = day.total
163                                    if use then
164                                        context([[draw textext("\strut\small\small\small%0.1f") shifted (%s,%s) ;]],use/1000,xoffset + 12,-7.5)
165                                        total = total + use
166                                    end
167                                end
168                            end
169                            for d=0,30 do
170                                local xoffset = d * 24
171                                context("draw (%s,%s) -- (%s,%s) withcolor darkgray ;",xoffset+ 0,0,xoffset+ 0,-10)
172                                context("draw (%s,%s) -- (%s,%s) withcolor darkgray ;",xoffset+ 6,0,xoffset+ 6,-2.5)
173                                context("draw (%s,%s) -- (%s,%s) withcolor darkgray ;",xoffset+12,0,xoffset+12,-5)
174                                context("draw (%s,%s) -- (%s,%s) withcolor darkgray ;",xoffset+18,0,xoffset+18,-2.5)
175                            end
176                            local xoffset = 31 * 24
177                            context("draw (%s,%s) -- (%s,%s) withcolor darkgray ;",xoffset,0,xoffset,-10)
178                        end
179
180                        grand = grand + total
181
182                        local max = (math.div(max,delta))
183
184                        for i=0,max*delta,delta do
185                            if i > 0 then
186                                context([[draw textext.lft("\hbox to 3.5em{\hss\strut%r}") shifted (%s,%s) ; ]],i,-10,i/scale)
187                            end
188                            context("draw (%s,%s) -- (%s,%s) withcolor .2white ;",0,i/scale,31 * 24,i/scale)
189                        end
190
191                        context([[draw textext    ("\strut\Word{%s}\enspace\emdash\enspace\month{%s}\enspace%s") shifted (%s,%s) ; ]],variant, m, y, 31 * 24 / 2, -50)
192                        context([[draw textext.lft("\hbox to 3.5em{\hss\strut%s}") shifted (%s,%s) ; ]],unit,-10,-25)
193                        context([[draw textext.lft("\hbox to 3.5em{\hss\strut\small\small\small%0.1f %s}") shifted (%s,%s) ;]],total/1000,unit == "watt" and "kWh" or [[m\high{3}]],-10, -7.5)
194                        context([[draw textext.lft("\hbox to 3.5em{\hss\strut\small\small\small\Sigma\nbsp%0.1f %s}") shifted (%s,%s) ;]],grand/1000,unit == "watt" and "kWh" or [[m\high{3}]],-10,-50.0)
195
196                        context.stopMPpage()
197                    else
198                        -- maybe placeholder
199                    end
200                end
201            end
202        end
203    end
204
205    function moduledata.youless.kwh(specification)
206        -- todo
207    end
208
209    function moduledata.youless.electricity(specification)
210        specification.unit    = "watt"
211        specification.maxunit = "maxwatt"
212        process(specification,"electricity")
213    end
214
215    moduledata.youless.watt = moduledata.youless.electricity
216
217    function moduledata.youless.gas(specification)
218        specification.unit    = "liters"
219        specification.maxunit = "maxliters"
220        process(specification,"gas")
221    end
222
223    function moduledata.youless.pulse(specification)
224        specification.unit    = "watt"
225        specification.maxunit = "maxwatt"
226        process(specification,"pulse")
227    end
228
229    function moduledata.youless.graphics(specification)
230        process(specification)
231    end
232
233\stopluacode
234
235\continueifinputfile{s-youless.mkiv}
236
237\setupbodyfont[dejavu] % smaller sizes also look ok
238
239% printer (oce)  : > 3000 W startup (900 W idle, 2000 W printing)
240% coffeemaker    :   1500 W when heating
241
242% baseline day   :   2250 W (servers, airco, workstations, routers, switches, heating, etc)
243% baseline night :   1750 W
244
245\starttext
246
247    \startluacode
248
249     -- os.execute([[mtxrun --script youless --collect --electricity "c:/data/system/youless/data/youless-electricity.lua"]])
250     -- os.execute([[mtxrun --script youless --collect --electricity --nobackup "c:/data/system/youless/data/youless-electricity.lua"]])
251     -- moduledata.youless.electricity { year = 2017, filename = "c:/data/system/youless/data/youless-electricity.lua" }
252
253        moduledata.youless.electricity { year = 2017, filename = "youless-electricity.lua" }
254
255    \stopluacode
256
257\stoptext
258