projectsimulator 0.2.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 024bbe43574b19e2cef1d32997464cb570ae9828559842a47980069503d4ccd4
4
- data.tar.gz: ac1aac4437f90007c016ef61e7b6bf89673d6d1310929e9557e1f334e730198d
3
+ metadata.gz: 850c1d323a1816a344d896177412330258c4b9bcbe8c946182701533efdddf05
4
+ data.tar.gz: 9e7a2e6ab061f4820207085240a52d8bd36847e57b6ef5d8cf0a625739802dad
5
5
  SHA512:
6
- metadata.gz: c18c8f2422750ffa91db344a0d9845633be16d23447599e9c73404bf2203335a110f0fa56f45cf5e552aa2ef66740c18d4d1de3ee9cdbca72d4602aaa203528b
7
- data.tar.gz: 349887e64fcd35c9bfadbb113e52cea58a7f781b58896e1888dd9763e064d9b38a4917e6622f9bee7334a1ebb186d1abda4048bfa4c154b448a6953507000892
6
+ metadata.gz: e52e950765845719638554324e058fdda5484feb34128aad13b76f8ff0623b5db4af437aaf60778e6b2356edb43533347831e7a78c3269500f61be6183946ca0
7
+ data.tar.gz: 55d386d448cd8edb318f938771505d2d61155d7106ebf48932469ffab840db66de019a0556bfe481206af055668326e111cfc04f50346aef7f48a16ac5b80740
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -2,10 +2,9 @@
2
2
 
3
3
  # file: projectsimulator.rb
4
4
 
5
- require 'rowx'
5
+
6
6
  require 'easydom'
7
7
  require 'app-routes'
8
- require 'chronic_between'
9
8
 
10
9
 
11
10
  module ProjectSimulator
@@ -13,12 +12,40 @@ module ProjectSimulator
13
12
  class Model
14
13
  include AppRoutes
15
14
 
16
- def initialize(obj=nil, root: 'building1')
15
+ def initialize(obj=nil, root: 'building1', debug: false)
17
16
 
18
17
  super()
19
- @root = root
18
+ @root, @debug = root, debug
20
19
  @location = nil
21
- build(obj, root: root) if obj
20
+
21
+ if obj then
22
+
23
+ s = obj.strip
24
+
25
+ puts 's: ' + s.inspect if @debug
26
+
27
+ if s[0] == '<' or s.lines[1][0..1] == ' ' then
28
+
29
+ puts 'before easydom' if @debug
30
+
31
+ s2 = if s.lines[1][0..1] == ' ' then
32
+
33
+ lines = s.lines.map do |line|
34
+ line.sub(/(\w+) +is +(\w+)$/) {|x| "#{$1} {switch: #{$2}}" }
35
+ end
36
+
37
+ lines.join
38
+
39
+ else
40
+ s
41
+ end
42
+
43
+ @ed = EasyDom.new(s2)
44
+ else
45
+ build(s, root: root)
46
+ end
47
+
48
+ end
22
49
 
23
50
  end
24
51
 
@@ -36,8 +63,27 @@ module ProjectSimulator
36
63
  status = a.inject(@ed) {|r,x| r.send(x)}.send(h[:action])
37
64
  "The %s %s is %s." % [h[:location], h[:device], status]
38
65
 
39
- end
66
+ end
40
67
 
68
+ def get_service(h)
69
+
70
+ a = []
71
+ a << h[:location].split(/ /) if h.has_key? :location
72
+ a << h[:service]
73
+ status = a.inject(@ed) {|r,x| r.send(x)}.send(h[:action])
74
+
75
+ if h.has_key? :location then
76
+ "The %s %s is %s." % [h[:location], h[:service], status]
77
+ else
78
+ "%s is %s." % [h[:service].capitalize, status]
79
+ end
80
+
81
+ end
82
+
83
+ # Object Property (op)
84
+ # Helpful for accessing properites in dot notation
85
+ # e.g. op.livingroom.light.switch = 'off'
86
+ #
41
87
  def op()
42
88
  @ed
43
89
  end
@@ -46,13 +92,16 @@ module ProjectSimulator
46
92
  @ed.e.element(s)
47
93
  end
48
94
 
95
+ # request accepts a string in plain english
96
+ # e.g. request 'switch the livingroom light on'
97
+ #
49
98
  def request(s)
50
99
 
51
100
  params = {request: s}
52
101
  requests(params)
53
102
  h = find_request(s)
54
103
 
55
- method(h.first[-1]).call(h)
104
+ method(h.first[-1]).call(h).gsub(/_/,' ')
56
105
 
57
106
  end
58
107
 
@@ -63,14 +112,49 @@ module ProjectSimulator
63
112
  a.inject(@ed) {|r,x| r.send(x)}.send(h[:action], h[:value])
64
113
 
65
114
  end
115
+
116
+ def set_service(h)
117
+
118
+ a = []
119
+ a += h[:location].split(/ /) if h[:location]
120
+ a << h[:service]
121
+ a.inject(@ed) {|r,x| r.send(x)}.send(h[:action], h[:value])
122
+
123
+ end
124
+
125
+ def to_sliml(level: 0)
126
+
127
+ s = @ed.to_sliml
66
128
 
67
- def to_sliml()
68
- @ed.to_sliml
129
+ return s if level.to_i > 0
130
+
131
+ lines = s.lines.map do |line|
132
+
133
+ line.sub(/\{[^\}]+\}/) do |x|
134
+
135
+ a = x.scan(/\w+: +[^ ]+/)
136
+ if a.length == 1 and x[/switch:/] then
137
+
138
+ val = x[/(?<=switch: ) *["']([^"']+)/,1]
139
+ 'is ' + val
140
+ else
141
+ x
142
+ end
143
+
144
+ end
145
+ end
146
+
147
+ lines.join
148
+
69
149
  end
70
150
 
71
- def xml(options=nil)
151
+ def to_xml(options=nil)
72
152
  @ed.xml(pretty: true).gsub(' style=\'\'','')
73
153
  end
154
+
155
+ alias xml to_xml
156
+
157
+ # to_xml() is the preferred method
74
158
 
75
159
  protected
76
160
 
@@ -85,20 +169,44 @@ module ProjectSimulator
85
169
  # e.g. switch the gas _fire off
86
170
  #
87
171
  get /(?:switch|turn) the ([^ ]+) +(on|off)$/ do |device, onoff|
88
- location = dev_location(device)
172
+ location = find_path(device)
89
173
  {type: :set_device, action: 'switch=', location: location, device: device, value: onoff}
90
- end
174
+ end
91
175
 
92
176
  # e.g. is the livingroom gas_fire on?
93
177
  #
94
178
  get /is the ([^ ]+) +([^ ]+) +(?:on|off)\??$/ do |location, device|
95
179
  {type: :get_device, action: 'switch', location: location, device: device}
96
180
  end
181
+
182
+ # e.g. enable airplane mode
183
+ #
184
+ get /((?:dis|en)able) ([^$]+)$/ do |state, rawservice|
185
+ service = rawservice.gsub(/ /,'_')
186
+ location = find_path(service)
187
+ {type: :set_service, action: 'switch=', location: location, service: service, value: state + 'd'}
188
+ end
189
+
190
+ # e.g. switch airplane mode off
191
+ #
192
+ get /switch (.*) (on|off)/ do |rawservice, rawstate|
193
+
194
+ state = rawstate == 'on' ? 'enabled' : 'disabled'
195
+ service = rawservice.gsub(/ /,'_')
196
+ location = find_path(service)
197
+ {type: :set_service, action: 'switch=', location: location, service: service, value: state}
198
+ end
199
+
200
+ # e.g. is airplane mode enabed?
201
+ #
202
+ get /is (.*) +(?:(?:dis|en)abled)\??$/ do |service|
203
+ {type: :get_service, action: 'switch', service: service.gsub(/ /,'_')}
204
+ end
97
205
 
98
206
  # e.g. is the gas_fire on?
99
207
  #
100
208
  get /is the ([^ ]+) +(?:on|off)\??$/ do |device|
101
- location = dev_location(device)
209
+ location = find_path(device)
102
210
  {type: :get_device, action: 'switch', location: location, device: device}
103
211
  end
104
212
 
@@ -111,7 +219,7 @@ module ProjectSimulator
111
219
  # e.g. fetch the temperature reading
112
220
  #
113
221
  get /fetch the ([^ ]+) +(?:reading)$/ do |device|
114
- location = dev_location(device)
222
+ location = find_path(device)
115
223
  {type: :get_device, action: 'reading', location: location, device: device}
116
224
  end
117
225
 
@@ -119,329 +227,55 @@ module ProjectSimulator
119
227
 
120
228
  private
121
229
 
122
- def dev_location(device)
123
- a = query('//'+ device).backtrack.to_xpath.split('/')
230
+ def find_path(s)
231
+ puts 'find_path s: ' + s.inspect if @debug
232
+ found = query('//'+ s)
233
+ return unless found
234
+ a = found.backtrack.to_xpath.split('/')
124
235
  a[1..-2].join(' ')
125
236
  end
126
237
 
127
238
  alias find_request run_route
128
239
 
129
240
  end
130
-
131
-
132
- class Event
133
241
 
242
+ class Controller
243
+
244
+ attr_reader :macros
134
245
  attr_accessor :title
135
- attr_reader :triggers, :actions, :constraints, :messages
136
-
137
- def initialize(e, time: nil, debug: false)
138
-
139
- @time, @debug = time, debug
140
- @title = e.text('event')
141
- @actions = []
142
- @triggers = []
143
- @constraints = []
144
246
 
145
- e.xpath('trigger/text()').each do |x|
146
- @triggers << Trigger.new(x, time: time, debug: debug).to_type
147
- end
148
-
149
- e.xpath('action/text()').each do |x|
150
- @actions << Action.new(x, debug: debug).to_type
151
- end
152
-
153
- e.xpath('constraint/text()').each do |x|
154
- puts 'before Constraints.new'
155
- @constraints << Constraint.new(x, time: time, debug: debug).to_type
156
- end
157
-
158
- end
159
-
160
- def match(trigger: nil, location: '')
161
-
162
- @messages = []
247
+ def initialize(mcs, debug: false)
163
248
 
164
- h = {motion: MotionTrigger}
165
-
166
- if @triggers.any? {|x| x.is_a? h[trigger.to_sym] and x.match } then
167
-
168
- if @constraints.all?(&:match) then
169
-
170
- @messages = @actions.map(&:call)
171
-
172
- else
173
-
174
- puts 'else reset?' if @debug
175
- a = @constraints.select {|x| x.is_a? FrequencyConstraint }
176
- puts 'a:' + a.inspect if @debug
177
- a.each {|x| x.reset if x.counter > 0 }
178
- return false
179
- end
180
-
181
- end
182
-
183
- end
184
-
185
- def time=(val)
186
- @time = val
187
- @constraints.each {|x| x.time = val if x.is_a? TimeConstraint }
188
- end
189
-
190
- end
191
-
192
- class Action
193
- include AppRoutes
194
-
195
- attr_reader :to_type
196
-
197
- def initialize(s, event: '', debug: false)
198
-
199
- super()
200
249
  @debug = debug
201
- params = {s: s, event: event}
202
- actions(params)
203
- @to_type = find_action(s) || {}
204
-
205
- end
206
-
207
- protected
208
-
209
- def actions(params)
210
-
211
- puts 'inside actions'
212
- # e.g. Say 'Good morning'
213
- #
214
- get /say ['"]([^'"]+)/i do |s|
215
- puts 's: ' + s.inspect if @debug
216
- SayAction.new(s)
217
- end
218
-
219
- # e.g. webhook entered_kitchen
220
- #
221
- get /webhook (.*)/i do |name|
222
- WebhookAction.new(name)
223
- end
224
-
225
- get /.*/ do
226
- puts 'action unknown' if @debug
227
- {}
228
- end
229
-
230
- end
231
-
232
- private
233
-
234
- alias find_action run_route
250
+ @syslog = []
251
+
252
+ @macros = mcs.macros
235
253
 
236
- end
237
-
238
- class Trigger
239
- include AppRoutes
240
-
241
- attr_reader :to_type
242
-
243
- def initialize(s, time: nil, debug: false)
244
-
245
- super()
246
- @time, @debug = time, debug
247
- params = {s: s}
248
- puts 'inside Trigger'
249
- puts 'params: ' + params.inspect
250
- triggers(params)
251
- @to_type = find_trigger(s)
252
-
253
- end
254
-
255
- protected
256
-
257
- def triggers(params)
258
-
259
- puts 'inside triggers'
260
-
261
- # e.g. Motion detected in the kitchen
262
- #
263
- get /motion detected in the (.*)/i do |location|
264
- puts 'motion detection trigger'
265
- MotionTrigger.new(location)
266
- end
267
-
268
- end
269
-
270
- private
271
-
272
- alias find_trigger run_route
273
-
274
- end
275
-
276
- class Constraint
277
- include AppRoutes
254
+ end
278
255
 
279
- attr_reader :to_type
280
-
281
- def initialize(s, time: nil, debug: false)
282
-
283
- super()
284
- @time, @debug = time, debug
285
-
286
- params = {s: s }
287
- constraints(params)
288
- @to_type = find_constraint(s)
289
-
290
- end
291
256
 
292
- protected
293
-
294
- def constraints(params)
295
-
296
- puts 'inside constraints' if @debug
297
- # e.g. Between 8am and 10am
298
- #
299
- get /^between (.*)/i do |s|
300
- TimeConstraint.new(s, time: @time)
301
- end
257
+ def trigger(name, detail={time: $env[:time]})
302
258
 
303
- get /^on a (.*)/i do |s|
304
- TimeConstraint.new(s, time: @time)
305
- end
306
-
307
- get /^(after .*)/i do |s|
308
- TimeConstraint.new(s, time: @time)
309
- end
310
-
311
- get /^once only/i do |s|
312
- FrequencyConstraint.new(1, debug: @debug)
313
- end
314
-
315
- end
316
-
317
- private
318
-
319
- alias find_constraint run_route
320
- end
321
-
322
- class MotionTrigger
323
-
324
- attr_reader :location
325
-
326
- def initialize(location)
327
- @location = location
328
- end
329
-
330
- def match()
331
- @location.downcase == location.downcase
332
- end
333
-
334
- end
335
-
336
- class SayAction
337
-
338
- def initialize(s)
339
- @s = s
340
- end
341
-
342
- def call()
343
- "say: %s" % @s
344
- end
345
-
346
- end
347
-
348
- class WebhookAction
349
-
350
- attr_accessor :url
351
-
352
- def initialize(name)
353
- @name = name
354
- @url = '127.0.0.1'
355
- end
356
-
357
- def call()
358
- "webhook: %s" % @url
359
- end
360
-
361
- end
362
-
363
- class TimeConstraint
364
-
365
- attr_accessor :time
366
-
367
- def initialize(times, time: nil)
368
- @times, @time = times, time
369
- end
370
-
371
- def match()
372
- ChronicBetween.new(@times).within?(@time)
373
- end
259
+ macros = @macros.select do |macro|
374
260
 
375
- end
261
+ puts 'macro: ' + macro.inspect if @debug
376
262
 
377
- class FrequencyConstraint
378
-
379
- def initialize(freq, debug: false)
380
- @freq, @debug = freq, debug
381
- @counter = 0
382
- end
383
-
384
- def counter()
385
- @counter
386
- end
387
-
388
- def increment()
389
- @counter += 1
390
- end
391
-
392
- def match()
393
- @counter < @freq
394
- end
395
-
396
- def reset()
397
- puts 'resetting' if @debug
398
- @foo = 0
399
- @counter = 0
400
- end
401
-
402
- end
403
-
404
- class Controller
405
-
406
- attr_reader :events
407
- attr_accessor :time
408
-
409
- def initialize(s, time: Time.now, debug: false)
410
-
411
- @time, @debug = time, debug
412
-
413
- doc = Rexle.new(RowX.new(s).to_xml)
414
-
415
- @events = doc.root.xpath('item')\
416
- .map {|e| Event.new(e, time: @time, debug: debug) }
417
-
418
- end
419
-
420
- def time=(val)
421
- @time = val
422
- @events.each {|event| event.time = val }
423
- end
424
-
425
- def trigger(name, location: '')
426
-
427
- events = @events.select do |event|
263
+ valid_trigger = macro.match?(name, detail)
428
264
 
429
- puts 'event: ' + event.inspect if @debug
430
-
431
- event.match(trigger: 'motion', location: location)
265
+ puts 'valid_trigger: ' + valid_trigger.inspect if @debug
266
+
267
+ if valid_trigger then
268
+ @syslog << [Time.now, :trigger, name]
269
+ @syslog << [Time.now, :macro, macro.title]
270
+ end
271
+
272
+ valid_trigger
432
273
 
433
274
  end
434
275
 
435
- puts 'events: ' + events.inspect if @debug
436
-
437
- events.each do |event|
438
- c = event.constraints.select {|x| x.is_a? FrequencyConstraint }
439
- puts 'c:' + c.inspect
440
- c.each(&:increment)
441
- end
442
-
443
- events.flat_map(&:messages)
276
+ puts 'macros: ' + macros.inspect if @debug
444
277
 
278
+ macros.flat_map(&:run)
445
279
  end
446
280
 
447
281
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: projectsimulator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -35,28 +35,8 @@ cert_chain:
35
35
  2GrtfOXGVOS+2jvmCQC6vU+ew9WBxiDUbebI95TeTwMs2o0cs3IASXX5rIn4TPcz
36
36
  SCccB3fVg2yfsy5DivaWaZwg
37
37
  -----END CERTIFICATE-----
38
- date: 2020-05-07 00:00:00.000000000 Z
38
+ date: 2020-08-20 00:00:00.000000000 Z
39
39
  dependencies:
40
- - !ruby/object:Gem::Dependency
41
- name: rowx
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: 0.7.0
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: '0.7'
50
- type: :runtime
51
- prerelease: false
52
- version_requirements: !ruby/object:Gem::Requirement
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: 0.7.0
57
- - - "~>"
58
- - !ruby/object:Gem::Version
59
- version: '0.7'
60
40
  - !ruby/object:Gem::Dependency
61
41
  name: easydom
62
42
  requirement: !ruby/object:Gem::Requirement
@@ -97,26 +77,6 @@ dependencies:
97
77
  - - ">="
98
78
  - !ruby/object:Gem::Version
99
79
  version: 0.1.19
100
- - !ruby/object:Gem::Dependency
101
- name: chronic_between
102
- requirement: !ruby/object:Gem::Requirement
103
- requirements:
104
- - - "~>"
105
- - !ruby/object:Gem::Version
106
- version: '0.3'
107
- - - ">="
108
- - !ruby/object:Gem::Version
109
- version: 0.3.1
110
- type: :runtime
111
- prerelease: false
112
- version_requirements: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - "~>"
115
- - !ruby/object:Gem::Version
116
- version: '0.3'
117
- - - ">="
118
- - !ruby/object:Gem::Version
119
- version: 0.3.1
120
80
  description:
121
81
  email: james@jamesrobertson.eu
122
82
  executables: []
metadata.gz.sig CHANGED
Binary file