projectsimulator 0.2.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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