ruby-macrodroid 0.6.0 → 0.7.4

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: dfb49da8914ecdd5cc21ca0223801fa0d432890a3df4c352ab7c3914c1bd63fe
4
- data.tar.gz: 9f402e6d1c9dbd17f5cb7d3741bcc7c487461a5438adf3cba81a71df9feb50f9
3
+ metadata.gz: e28ec7303f297d90ed5edbbec3806c577d1fe3036851620c230b4620d4a8a98f
4
+ data.tar.gz: fd27b2da1d660144aae8bc85b3f392b10b385934d1a38f65817d53ff774e382c
5
5
  SHA512:
6
- metadata.gz: 0753ef46f3cdbc1e5a8fb6539747e662a2e537089aa83e32ecf47c89334b1acb71ced47f77230e1fcae00314d8dd70e8e4d37380c27f25ebb0ccafe837121daa
7
- data.tar.gz: e78f3fc06bcdbd1685de98d5473b2564d904a722053527505002f5a5bbfa43e51e99832d2a9a29eb5a12d3e9bab94d91429f78628625e74acbae6876b909f43a
6
+ metadata.gz: f727092bb6f96799f1cd288e5ebf822b189d70ef2b5bcdb5bab452b93b412b737229fa6fed2d982f1233aa5f21d35fb1791e834d8ea023474c1eac6a3d330fd5
7
+ data.tar.gz: 706f9423e28c7fda560bf059f4686834e4404dca9576d5682f3e43c82440a79c84e5ddeb65619a5410098993da1ee9574cc681912a94285147b40aba1468f8a8
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -2,11 +2,121 @@
2
2
 
3
3
  # file: ruby-macrodroid.rb
4
4
 
5
- require 'uuid'
5
+ # This file contains the following classes:
6
+ #
7
+ # ## Nlp classes
8
+ #
9
+ # TriggersNlp ActionsNlp ConstraintsNlp
10
+ #
11
+ #
12
+ # ## Macro class
13
+ #
14
+ # Macro
15
+ #
16
+ #
17
+ # ## Error class
18
+ #
19
+ # MacroDroidError
20
+ #
21
+ #
22
+ # ## Droid class
23
+ #
24
+ # MacroDroid
25
+ #
26
+ #
27
+ # ## Map class
28
+ #
29
+ # GeofenceMap
30
+ #
31
+ #
32
+ # ## Object class
33
+ #
34
+ # MacroObject
35
+ #
36
+ #
37
+ # ## Trigger classes
38
+ #
39
+ # Trigger WebHookTrigger WifiConnectionTrigger
40
+ # ApplicationInstalledRemovedTrigger ApplicationLaunchedTrigger
41
+ # BatteryLevelTrigger BatteryTemperatureTrigger PowerButtonToggleTrigger
42
+ # ExternalPowerTrigger CallActiveTrigger IncomingCallTrigger
43
+ # OutgoingCallTrigger CallEndedTrigger CallMissedTrigger IncomingSMSTrigger
44
+ # WebHookTrigger WifiConnectionTrigger BluetoothTrigger HeadphonesTrigger
45
+ # SignalOnOffTrigger UsbDeviceConnectionTrigger WifiSSIDTrigger
46
+ # CalendarTrigger TimerTrigger StopwatchTrigger DayTrigger
47
+ # RegularIntervalTrigger DeviceEventsTrigger AirplaneModeTrigger
48
+ # AutoSyncChangeTrigger DayDreamTrigger DockTrigger FailedLoginTrigger
49
+ # GPSEnabledTrigger MusicPlayingTrigger DeviceUnlockedTrigger
50
+ # AutoRotateChangeTrigger ClipboardChangeTrigger BootTrigger
51
+ # IntentReceivedTrigger NotificationTrigger ScreenOnOffTrigger
52
+ # SilentModeTrigger WeatherTrigger GeofenceTrigger SunriseSunsetTrigger
53
+ # SensorsTrigger ActivityRecognitionTrigger ProximityTrigger
54
+ # ShakeDeviceTrigger FlipDeviceTrigger OrientationTrigger
55
+ # FloatingButtonTrigger ShortcutTrigger VolumeButtonTrigger
56
+ # MediaButtonPressedTrigger SwipeTrigger
57
+ #
58
+ #
59
+ # ## Action classes
60
+ #
61
+ # Action LocationAction ShareLocationAction ApplicationAction
62
+ # LaunchActivityAction KillBackgroundAppAction OpenWebPageAction CameraAction
63
+ # UploadPhotoAction TakePictureAction ConnectivityAction SetWifiAction
64
+ # SetBluetoothAction SetBluetoothAction SendIntentAction DateTimeAction
65
+ # SetAlarmClockAction StopWatchAction SayTimeAction DeviceAction
66
+ # AndroidShortcutsAction ClipboardAction PressBackAction SpeakTextAction
67
+ # UIInteractionAction VoiceSearchAction DeviceSettingsAction
68
+ # ExpandCollapseStatusBarAction LaunchHomeScreenAction CameraFlashLightAction
69
+ # VibrateAction SetAutoRotateAction DayDreamAction SetKeyboardAction
70
+ # SetKeyguardAction CarModeAction ChangeKeyboardAction SetWallpaperAction
71
+ # FileAction OpenFileAction LocationAction ForceLocationUpdateAction
72
+ # ShareLocationAction SetLocationUpdateRateAction LoggingAction
73
+ # AddCalendarEntryAction LogAction ClearLogAction MediaAction
74
+ # RecordMicrophoneAction PlaySoundAction MessagingAction SendEmailAction
75
+ # SendSMSAction UDPCommandAction NotificationsAction ClearNotificationsAction
76
+ # MessageDialogAction AllowLEDNotificationLightAction
77
+ # SetNotificationSoundAction SetNotificationSoundAction
78
+ # SetNotificationSoundAction NotificationAction ToastAction PhoneAction
79
+ # AnswerCallAction ClearCallLogAction OpenCallLogAction RejectCallAction
80
+ # MakeCallAction SetRingtoneAction ScreenAction SetBrightnessAction
81
+ # ForceScreenRotationAction ScreenOnAction DimScreenAction KeepAwakeAction
82
+ # SetScreenTimeoutAction VolumeAction SilentModeVibrateOffAction
83
+ # SetVibrateAction VolumeIncrementDecrementAction SpeakerPhoneAction
84
+ # SetVolumeAction
85
+ #
86
+ #
87
+ # ## Constraint classes
88
+ #
89
+ # Constraint TimeOfDayConstraint BatteryLevelConstraint
90
+ # BatterySaverStateConstraint BatteryTemperatureConstraint
91
+ # ExternalPowerConstraint BluetoothConstraint GPSEnabledConstraint
92
+ # LocationModeConstraint SignalOnOffConstraint WifiConstraint
93
+ # CellTowerConstraint IsRoamingConstraint DataOnOffConstraint
94
+ # WifiHotSpotConstraint CalendarConstraint DayOfWeekConstraint
95
+ # TimeOfDayConstraint DayOfMonthConstraint MonthOfYearConstraint
96
+ # SunsetSunriseConstraint AirplaneModeConstraint AutoRotateConstraint
97
+ # DeviceLockedConstraint RoamingOnOffConstraint TimeSinceBootConstraint
98
+ # AutoSyncConstraint NFCStateConstraint IsRootedConstraint VpnConstraint
99
+ # MacroEnabledConstraint ModeConstraint TriggerThatInvokedConstraint
100
+ # LastRunTimeConstraint HeadphonesConnectionConstraint MusicActiveConstraint
101
+ # NotificationPresentConstraint PriorityModeConstraint
102
+ # NotificationVolumeConstraint InCallConstraint PhoneRingingConstraint
103
+ # BrightnessConstraint VolumeConstraint SpeakerPhoneConstraint
104
+ # DarkThemeConstraint ScreenOnOffConstraint VolumeLevelConstraint
105
+ # FaceUpDownConstraint LightLevelConstraint DeviceOrientationConstraint
106
+ # ProximitySensorConstraint
107
+
108
+
109
+
6
110
  require 'yaml'
7
- require 'glw'
8
- require 'geozone'
9
- require 'rxfhelper'
111
+ require 'rowx'
112
+ require 'uuid'
113
+ #require 'glw'
114
+ #require 'geozone'
115
+ require 'subunit'
116
+ #require 'rxfhelper'
117
+ require 'requestor'
118
+ eval Requestor.read('http://a0.jamesrobertson.eu/rorb/r/ruby'){|x| x.require 'rxfhelper' }
119
+
10
120
  require 'chronic_cron'
11
121
 
12
122
 
@@ -68,6 +178,20 @@ class TriggersNlp
68
178
  [GeofenceTrigger, {name: name, enter_area: enter_area}]
69
179
  end
70
180
 
181
+ get /^location (entered|exited) \(([^\)]+)/i do |direction, name|
182
+ enter_area = direction.downcase.to_sym == :entered
183
+ [GeofenceTrigger, {name: name, enter_area: enter_area}]
184
+ end
185
+
186
+ # eg. Proximity Sensor (Near)
187
+ #
188
+ get /^Proximity Sensor \(([^\)]+)\)/i do |distance|
189
+
190
+ [ProximityTrigger, {distance: distance}]
191
+ end
192
+
193
+
194
+
71
195
  end
72
196
 
73
197
  alias find_trigger run_route
@@ -153,6 +277,38 @@ class ActionsNlp
153
277
  [OpenWebPageAction, url_to_open: url]
154
278
 
155
279
  end
280
+
281
+ # e.g. webhook entered_kitchen
282
+ #
283
+ get /webhook|HTTP GET/i do
284
+ [OpenWebPageAction, {}]
285
+ end
286
+
287
+ #a: Keep Device Awake Screen On Until Disabled
288
+ #
289
+ get /Keep Device Awake Screen On Until Disabled/i do
290
+ [KeepAwakeAction, {enabled: true, permanent: true, screen_option: 0}]
291
+ end
292
+
293
+
294
+ #a: Keep Device Awake Screen On 1h 1m 1s
295
+ #
296
+ get /Keep Device Awake Screen On ([^$]+)/i do |duration|
297
+
298
+ a = duration.split.map(&:to_i)
299
+ secs = Subunit.new(units={minutes:60, hours:60, seconds: 60}, a).to_i
300
+
301
+ h = {
302
+ permanent: true, screen_option: 0, seconds_to_stay_awake_for: secs
303
+ }
304
+ [KeepAwakeAction, h]
305
+ end
306
+
307
+ #a: Disable Keep Awake
308
+ #
309
+ get /Disable Keep Awake/i do
310
+ [KeepAwakeAction, {enabled: false, screen_option: 0}]
311
+ end
156
312
 
157
313
 
158
314
  end
@@ -244,9 +400,9 @@ class Macro
244
400
  attr_reader :local_variables, :triggers, :actions, :constraints, :guid
245
401
  attr_accessor :title, :description
246
402
 
247
- def initialize(name=nil, geofence: geofence, debug: false)
403
+ def initialize(name=nil, geofences: geofences, debug: false)
248
404
 
249
- @title, @geofence, @debug = name, geofence, debug
405
+ @title, @geofences, @debug = name, geofences, debug
250
406
 
251
407
  puts 'inside Macro#initialize' if @debug
252
408
 
@@ -337,19 +493,20 @@ class Macro
337
493
  end
338
494
 
339
495
  def import_xml(node)
340
-
496
+
341
497
  if @debug then
342
498
  puts 'inside Macro#import_xml'
343
499
  puts 'node: ' + node.xml.inspect
344
500
  end
345
501
 
346
- @title = node.attributes[:name]
347
- @description = node.attributes[:description]
348
-
349
502
  if node.element('triggers') then
350
-
503
+
351
504
  # level 2
352
505
 
506
+ @title = node.attributes[:name]
507
+ @description = node.attributes[:description]
508
+
509
+
353
510
  # get all the triggers
354
511
  @triggers = node.xpath('triggers/*').map do |e|
355
512
 
@@ -385,6 +542,12 @@ class Macro
385
542
 
386
543
  # Level 1
387
544
 
545
+ puts 'import_xml: inside level 1' if @debug
546
+
547
+ @title = node.text('macro') || node.attributes[:name]
548
+
549
+ #@description = node.attributes[:description]
550
+
388
551
  tp = TriggersNlp.new
389
552
 
390
553
  @triggers = node.xpath('trigger').map do |e|
@@ -394,7 +557,11 @@ class Macro
394
557
  puts 'found trigger ' + r.inspect if @debug
395
558
 
396
559
  if r then
397
- r[0].new(r[1])
560
+ if r[0] == GeofenceTrigger then
561
+ GeofenceTrigger.new(r[1], geofences: @geofences)
562
+ else
563
+ r[0].new(r[1])
564
+ end
398
565
  end
399
566
 
400
567
  end
@@ -403,11 +570,21 @@ class Macro
403
570
 
404
571
  @actions = node.xpath('action').map do |e|
405
572
 
573
+ puts 'action e: ' + e.xml.inspect if @debug
406
574
  r = ap.find_action e.text
407
575
  puts 'found action ' + r.inspect if @debug
408
576
 
409
577
  if r then
410
- r[0].new(r[1])
578
+
579
+ a = e.xpath('item/*')
580
+
581
+ h = if a.any? then
582
+ a.map {|node| [node.name.to_sym, node.text.to_s]}.to_h
583
+ else
584
+ {}
585
+ end
586
+
587
+ r[0].new(r[1].merge(h))
411
588
  end
412
589
 
413
590
  end
@@ -485,18 +662,56 @@ EOF
485
662
 
486
663
  def to_s()
487
664
 
665
+ indent = 0
666
+ actions = @actions.map do |x|
667
+
668
+ s = x.to_s
669
+
670
+ r = if indent <= 0 then
671
+
672
+ "a: %s" % s
673
+
674
+ elsif indent > 0
675
+
676
+ if s =~ /^Else/ then
677
+ (' ' * (indent-1)) + "%s" % s
678
+ elsif s =~ /^End/
679
+ indent -= 1
680
+ (' ' * indent) + "%s" % s
681
+ else
682
+ (' ' * indent) + "%s" % s
683
+ end
684
+
685
+ end
686
+
687
+ if s =~ /^If/i then
688
+ if indent < 1 then
689
+ r = "a:\n %s" % s
690
+ indent += 1
691
+ else
692
+ r = (' ' * indent) + "%s" % s
693
+ end
694
+
695
+ indent += 1
696
+ end
697
+
698
+ r
699
+
700
+ end.join("\n")
701
+
488
702
  a = [
489
703
  'm: ' + @title,
490
704
  @triggers.map {|x| "t: %s" % x}.join("\n"),
491
- @actions.map {|x| "a: %s" % x}.join("\n"),
492
- @constraints.map {|x| "a: %s" % x}.join("\n")
705
+ actions
493
706
  ]
494
707
 
708
+ a << @constraints.map {|x| "c: %s" % x}.join("\n") if @constraints.any?
709
+
495
710
  if @description and @description.length >= 1 then
496
- a.insert(1, 'd: ' + @description)
711
+ a.insert(1, 'd: ' + @description.gsub(/\n/,"\n "))
497
712
  end
498
713
 
499
- a.join("\n")
714
+ a.join("\n") + "\n"
500
715
 
501
716
  end
502
717
 
@@ -504,11 +719,11 @@ EOF
504
719
 
505
720
  a = [
506
721
  'm: ' + @title,
507
- 't: ' + @triggers.map(&:to_s).join(", "),
508
- 'a: ' + @actions.map(&:to_s).join(", "),
722
+ 't: ' + @triggers.map(&:to_summary).join(", "),
723
+ 'a: ' + @actions.map(&:to_summary).join(", "),
509
724
  ]
510
725
 
511
- a << 'c: ' + @constraints.map(&:to_s).join(", ") if @constraints.any?
726
+ a << 'c: ' + @constraints.map(&:to_summary).join(", ") if @constraints.any?
512
727
 
513
728
  a.join("\n") + "\n"
514
729
 
@@ -528,7 +743,7 @@ EOF
528
743
 
529
744
  if klass == GeofenceTrigger then
530
745
  puts 'GeofenceTrigger found'.highlight if $debug
531
- klass.new(@geofence, h)
746
+ GeofenceTrigger.new(h, geofences: @geofences)
532
747
  else
533
748
  klass.new h
534
749
  end
@@ -545,12 +760,14 @@ class MacroDroid
545
760
  using ColouredText
546
761
  using Params
547
762
 
548
- attr_reader :macros, :geofence
763
+ attr_reader :macros, :geofences, :yaml
549
764
 
550
765
  def initialize(obj=nil, debug: false)
551
766
 
552
767
  @debug = debug
553
768
 
769
+ @geofences = {}
770
+
554
771
  if obj then
555
772
 
556
773
  raw_s, _ = RXFHelper.read(obj)
@@ -570,18 +787,37 @@ class MacroDroid
570
787
 
571
788
  puts 's: ' + s.inspect if @debug
572
789
 
573
- xml = if s =~ /m:\s/ then
574
- puts 'before text_to_xml' if @debug
575
- text_to_xml(s)
790
+ if s =~ /m(?:acro)?:\s/ then
791
+
792
+ puts 'before RowX.new' if @debug
793
+
794
+ s2 = s.gsub(/^g:/,'geofence:').gsub(/^m:/,'macro:')\
795
+ .gsub(/^t:/,'trigger:').gsub(/^a:/,'action:')\
796
+ .gsub(/^c:/,'constraint:').gsub(/^#.*/,'')
797
+
798
+ raw_macros, raw_geofences = s2.split(/(?=^macro:)/,2).reverse
799
+
800
+ if raw_geofences then
801
+
802
+ geoxml = RowX.new(raw_geofences).to_xml
803
+
804
+ geodoc = Rexle.new(geoxml)
805
+ geofences = geodoc.root.xpath('item/geofence')
806
+ @geofences = fetch_geofences(geofences) if geofences.any?
807
+
808
+ end
809
+
810
+ xml = RowX.new(raw_macros).to_xml
811
+ import_rowxml(xml)
812
+
576
813
  elsif s =~ /^# /
577
- pc_to_xml(s)
814
+ xml = pc_to_xml(s)
815
+ import_xml(xml)
578
816
  else
579
817
  raise MacroDroidError, 'invalid input'
580
818
  end
581
- import_xml(xml)
582
- @h = build_h
583
819
 
584
-
820
+ @h = build_h
585
821
 
586
822
  end
587
823
 
@@ -637,7 +873,13 @@ class MacroDroid
637
873
 
638
874
  def to_h()
639
875
 
640
- @h.merge(macro_list: @macros.map(&:to_h)).to_camel_case
876
+ h = {
877
+ geofence_data: {
878
+ geofence_map: @geofences.map {|key, value| [key, value.to_h] }.to_h
879
+ },
880
+ macro_list: @macros.map(&:to_h)
881
+ }
882
+ @h.merge(h).to_camel_case
641
883
 
642
884
  end
643
885
 
@@ -648,7 +890,16 @@ class MacroDroid
648
890
  end
649
891
 
650
892
  def to_s()
651
- @macros.map(&:to_s).join("\n")
893
+
894
+ lines = []
895
+
896
+ if @geofences.any? then
897
+ lines << @geofences.map {|_, value| 'g: ' + value.to_s}.join("\n\n") + "\n"
898
+ end
899
+
900
+ lines << @macros.map(&:to_s).join("\n")
901
+ lines.join("\n")
902
+
652
903
  end
653
904
 
654
905
  def to_summary()
@@ -657,10 +908,37 @@ class MacroDroid
657
908
 
658
909
  private
659
910
 
911
+ def fetch_geofences(nodes)
912
+
913
+ nodes.map do |e|
914
+
915
+ name = e.text.to_s.strip
916
+ item = e.element('item')
917
+ coordinates = item.text('coordinates')
918
+ latitude, longitude = coordinates.split(/, */,2)
919
+ radius = item.text('radius')
920
+
921
+ id = UUID.new.generate
922
+
923
+ h = {
924
+ name: name,
925
+ longitude: longitude,
926
+ latitude: latitude,
927
+ radius: radius,
928
+ id: id
929
+ }
930
+
931
+ [id.to_sym, GeofenceMap.new(h)]
932
+
933
+ end.to_h
934
+
935
+ end
936
+
660
937
  def import_json(s)
661
938
 
662
939
  h = JSON.parse(s, symbolize_names: true)
663
940
  puts 'json_to_yaml: ' + h.to_yaml if @debug
941
+ @yaml = h.to_yaml # helpful for debugging and testing
664
942
 
665
943
  @h = h.to_snake_case
666
944
  puts ('@h: ' + @h.inspect).debug if @debug
@@ -669,7 +947,7 @@ class MacroDroid
669
947
  # fetch the geofence data
670
948
  if @h[:geofence_data] then
671
949
 
672
- @geofence = @h[:geofence_data][:geofence_map].map do |id, properties|
950
+ @geofences = @h[:geofence_data][:geofence_map].map do |id, properties|
673
951
  [id, GeofenceMap.new(properties)]
674
952
  end.to_h
675
953
 
@@ -678,9 +956,9 @@ class MacroDroid
678
956
  @macros = @h[:macro_list].map do |macro|
679
957
 
680
958
  puts ('macro: ' + macro.inspect).debug if @debug
681
- puts '@geofence: ' + @geofence.inspect if @debug
959
+ # puts '@geofences: ' + @geofences.inspect if @debug
682
960
 
683
- m = Macro.new(geofence: @geofence, debug: @debug )
961
+ m = Macro.new(geofences: @geofences.map(&:last), debug: @debug )
684
962
  m.import_h(macro)
685
963
  m
686
964
 
@@ -690,9 +968,30 @@ class MacroDroid
690
968
 
691
969
  end
692
970
 
971
+ def import_rowxml(raws)
972
+
973
+ s = RXFHelper.read(raws).first
974
+ puts 's: ' + s.inspect if @debug
975
+ doc = Rexle.new(s)
976
+ puts 'after doc' if @debug
977
+ puts 'import_rowxml: @geofences: ' + @geofences.inspect if @debug
978
+ geofences = @geofences
979
+
980
+ @macros = doc.root.xpath('item').map do |node|
981
+ puts ('geofences: ' + geofences.inspect).highlight if @debug
982
+ Macro.new(geofences: geofences.map(&:last), debug: @debug).import_xml(node)
983
+
984
+ end
985
+
986
+ end
987
+
693
988
  def import_xml(raws)
694
989
 
695
- puts 'raws: ' + raws.inspect if @debug
990
+ if @debug then
991
+ puts 'inside import_xml'
992
+
993
+ puts 'raws: ' + raws.inspect
994
+ end
696
995
  s = RXFHelper.read(raws).first
697
996
  puts 's: ' + s.inspect if @debug
698
997
  doc = Rexle.new(s)
@@ -700,14 +999,10 @@ class MacroDroid
700
999
  if @debug then
701
1000
  puts 'doc: ' + doc.root.xml
702
1001
  end
703
-
704
- debug = @debug
705
-
1002
+
706
1003
  @macros = doc.root.xpath('macro').map do |node|
707
1004
 
708
- macro = Macro.new @title, debug: debug
709
- macro.import_xml(node)
710
- macro
1005
+ Macro.new(geofences: @geofences.map(&:last), debug: @debug).import_xml(node)
711
1006
 
712
1007
  end
713
1008
  end
@@ -732,36 +1027,7 @@ class MacroDroid
732
1027
  doc = Rexle.new([:macros, {}, '', *macros])
733
1028
  doc.root.xml pretty: true
734
1029
 
735
- end
736
-
737
- def text_to_xml(s)
738
-
739
- a = s.split(/.*(?=^m:)/)
740
- puts 'a : ' + a.inspect if @debug
741
- a.map!(&:chomp)
742
-
743
- macros = a.map do |x|
744
-
745
- lines = x.lines
746
- puts 'lines: ' + lines.inspect if @debug
747
-
748
- name = lines.shift[/^m: +(.*)/,1]
749
- h = {t: [], a: [], c: []}
750
-
751
- lines.each {|line| h[line[0].to_sym] << line[/^\w: +(.*)/,1] }
752
- triggers = h[:t].map {|text| [:trigger, {}, text]}
753
- actions = h[:a].map {|text| [:action, {}, text]}
754
- constraints = h[:c].map {|text| [:constraint, {}, text]}
755
-
756
- [:macro, {name: name},'', *triggers, *actions, *constraints]
757
-
758
- end
759
-
760
- doc = Rexle.new([:macros, {}, '', *macros])
761
- doc.root.xml pretty: true
762
-
763
- end
764
-
1030
+ end
765
1031
 
766
1032
  end
767
1033
 
@@ -769,8 +1035,30 @@ class GeofenceMap
769
1035
 
770
1036
  attr_accessor :name, :longitude, :latitude, :radius, :id
771
1037
 
772
- def initialize(h)
773
- @id, @latitude, @longitude, @name, @radius = h.values
1038
+ def initialize(id: '', longitude: '', latitude: '', name: '', radius: '')
1039
+
1040
+ @id, @latitude, @longitude, @name, @radius = id, latitude, \
1041
+ longitude, name, radius
1042
+
1043
+ end
1044
+
1045
+ def to_h()
1046
+
1047
+ {
1048
+ id: @id,
1049
+ longitude: @longitude,
1050
+ latitude: @latitude,
1051
+ name: @name,
1052
+ radius: @radius
1053
+ }
1054
+
1055
+ end
1056
+
1057
+ def to_s()
1058
+
1059
+ coordinates = "%s, %s" % [@longitude, @latitude]
1060
+ "%s\n coordinates: %s\n radius: %s" % [@name, coordinates, @radius]
1061
+
774
1062
  end
775
1063
 
776
1064
  end
@@ -817,6 +1105,8 @@ class MacroObject
817
1105
  def to_s()
818
1106
  "#<%s %s>" % [self.class, @h.inspect]
819
1107
  end
1108
+
1109
+ alias to_summary to_s
820
1110
 
821
1111
  protected
822
1112
 
@@ -831,13 +1121,32 @@ class MacroObject
831
1121
  UUID.new.generate
832
1122
  end
833
1123
 
1124
+ def object(h={})
1125
+
1126
+ puts ('inside object h:' + h.inspect).debug if @debug
1127
+ klass = Object.const_get h[:class_type]
1128
+ puts klass.inspect.highlight if $debug
1129
+
1130
+ klass.new h
1131
+
1132
+ end
1133
+
834
1134
  end
835
1135
 
836
1136
  class Trigger < MacroObject
837
-
1137
+ using Params
1138
+
1139
+ attr_reader :constraints
1140
+
838
1141
  def initialize(h={})
839
1142
  super({fakeIcon: 0}.merge(h))
840
1143
  @list << 'fakeIcon'
1144
+
1145
+ # fetch the constraints
1146
+ @constraints = @h[:constraint_list].map do |constraint|
1147
+ object(constraint.to_snake_case)
1148
+ end
1149
+
841
1150
  end
842
1151
 
843
1152
  def match?(detail={}, model=nil)
@@ -950,6 +1259,11 @@ class BatteryLevelTrigger < Trigger
950
1259
  super(options.merge h)
951
1260
 
952
1261
  end
1262
+
1263
+ def to_s()
1264
+ operator = @h[:decreases_to] ? '<=' : '>='
1265
+ "Battery %s %s%%" % [operator, @h[:battery_level]]
1266
+ end
953
1267
 
954
1268
  end
955
1269
 
@@ -1597,6 +1911,10 @@ class DeviceUnlockedTrigger < DeviceEventsTrigger
1597
1911
  super(options.merge h)
1598
1912
 
1599
1913
  end
1914
+
1915
+ def to_s()
1916
+ 'Screen Unlocked'
1917
+ end
1600
1918
 
1601
1919
  end
1602
1920
 
@@ -1755,12 +2073,12 @@ end
1755
2073
  #
1756
2074
  class GeofenceTrigger < Trigger
1757
2075
 
1758
- def initialize(geofence, h={})
2076
+ def initialize( h={}, geofences: {})
1759
2077
 
1760
2078
  if h[:name] then
1761
-
1762
- found = geofence.find {|x| x.name == h[:name]}
1763
- h[:geofence_id] = found.id
2079
+ puts ('geofences2: ' + geofences.inspect)
2080
+ found = geofences.find {|x| x.name.downcase == h[:name].downcase}
2081
+ h[:geofence_id] = found.id if found
1764
2082
 
1765
2083
  end
1766
2084
 
@@ -1773,15 +2091,25 @@ class GeofenceTrigger < Trigger
1773
2091
  }
1774
2092
 
1775
2093
  super(options.merge filter(options, h))
1776
- @geofence = geofence
2094
+ @geofences = geofences
1777
2095
 
1778
2096
  end
1779
2097
 
1780
2098
  def to_s()
1781
2099
 
1782
- puts ' @geofence: ' + @geofence.inspect if $debug
2100
+ if $debug then
2101
+ puts ' @geofences: ' + @geofences.inspect
2102
+ puts '@h: ' + @h.inspect
2103
+ puts '@h[:geofence_id]: ' + @h[:geofence_id].inspect
2104
+ end
2105
+
1783
2106
  direction = @h[:enter_area] ? 'Entry' : 'Exit'
1784
- "Geofence %s (%s)" % [direction, @geofence[@h[:geofence_id].to_sym].name]
2107
+
2108
+ found = @geofences.find {|x| x.id == @h[:geofence_id]}
2109
+ puts 'found: ' + found.inspect if @debug
2110
+ label = found ? found.name : 'error: name not found'
2111
+
2112
+ "Geofence %s (%s)" % [direction, label]
1785
2113
 
1786
2114
  end
1787
2115
 
@@ -1826,8 +2154,28 @@ class ActivityRecognitionTrigger < SensorsTrigger
1826
2154
  }
1827
2155
 
1828
2156
  super(options.merge h)
2157
+
2158
+ @activity = ['In Vehicle', 'On Bicycle', 'Running', 'Walking', 'Still']
1829
2159
 
1830
2160
  end
2161
+
2162
+ def to_s()
2163
+ activity = @activity[@h[:selected_index]]
2164
+ 'Activity - ' + activity
2165
+ end
2166
+
2167
+ def to_summary
2168
+
2169
+ activity = @activity[@h[:selected_index]]
2170
+ s = if activity.length > 10 then
2171
+ activity[0..7] + '..'
2172
+ else
2173
+ activity
2174
+ end
2175
+
2176
+ 'Activity - ' + s
2177
+
2178
+ end
1831
2179
 
1832
2180
  end
1833
2181
 
@@ -1837,14 +2185,33 @@ class ProximityTrigger < SensorsTrigger
1837
2185
 
1838
2186
  def initialize(h={})
1839
2187
 
2188
+ if h[:distance] then
2189
+
2190
+ case h[:distance].to_sym
2191
+ when :near
2192
+ options[:near] = true
2193
+ end
2194
+ end
2195
+
1840
2196
  options = {
1841
2197
  near: true,
1842
2198
  selected_option: 0
1843
2199
  }
1844
2200
 
1845
- super(options.merge h)
2201
+ super(options.merge filter(options,h))
1846
2202
 
1847
2203
  end
2204
+
2205
+ def to_s()
2206
+
2207
+ distance = if @h[:near] then
2208
+ 'Near'
2209
+ else
2210
+ 'Far'
2211
+ end
2212
+
2213
+ "Proximity Sensor (%s)" % distance
2214
+ end
1848
2215
 
1849
2216
  end
1850
2217
 
@@ -2017,9 +2384,17 @@ end
2017
2384
 
2018
2385
 
2019
2386
  class Action < MacroObject
2387
+ using Params
2388
+
2389
+ attr_reader :constraints
2020
2390
 
2021
2391
  def initialize(h={})
2022
2392
  super(h)
2393
+
2394
+ # fetch the constraints
2395
+ @constraints = @h[:constraint_list].map do |constraint|
2396
+ object(constraint.to_snake_case)
2397
+ end
2023
2398
  end
2024
2399
 
2025
2400
  def invoke(s='')
@@ -2117,6 +2492,8 @@ end
2117
2492
  class OpenWebPageAction < ApplicationAction
2118
2493
 
2119
2494
  def initialize(h={})
2495
+
2496
+ h[:url_to_open] = h[:url] if h[:url]
2120
2497
 
2121
2498
  options = {
2122
2499
  variable_to_save_response: {:m_stringValue=>"", :m_name=>"", :m_decimalValue=>0.0, :isLocal=>true, :m_booleanValue=>false, :excludeFromLog=>false, :m_intValue=>0, :m_type=>2},
@@ -2126,12 +2503,12 @@ class OpenWebPageAction < ApplicationAction
2126
2503
  block_next_action: false
2127
2504
  }
2128
2505
 
2129
- super(options.merge h)
2506
+ super(options.merge filter(options,h))
2130
2507
 
2131
2508
  end
2132
2509
 
2133
2510
  def to_s()
2134
- 'HTTP GET'
2511
+ "HTTP GET\n url: " + @h[:url_to_open]
2135
2512
  end
2136
2513
 
2137
2514
  end
@@ -2192,6 +2569,64 @@ class TakePictureAction < CameraAction
2192
2569
 
2193
2570
  end
2194
2571
 
2572
+ class IfConditionAction < Action
2573
+
2574
+ def initialize(h={})
2575
+
2576
+ options = {
2577
+ a: true,
2578
+ constraint_list: ''
2579
+ }
2580
+
2581
+ super(options.merge h)
2582
+
2583
+ end
2584
+
2585
+ def to_s()
2586
+
2587
+ operator = @h[:is_or_condition] ? 'OR' : 'AND'
2588
+ r = 'If ' + @constraints.map(&:to_s).join(" %s " % operator)
2589
+ puts 'if ... @h ' + @h.inspect
2590
+ r
2591
+
2592
+ end
2593
+ end
2594
+
2595
+ class ElseAction < Action
2596
+
2597
+ def initialize(h={})
2598
+
2599
+ options = {
2600
+ constraint_list: ''
2601
+ }
2602
+
2603
+ super(options.merge h)
2604
+
2605
+ end
2606
+
2607
+ def to_s()
2608
+ 'Else'
2609
+ end
2610
+
2611
+ end
2612
+
2613
+ class EndIfAction < Action
2614
+
2615
+ def initialize(h={})
2616
+
2617
+ options = {
2618
+ constraint_list: ''
2619
+ }
2620
+
2621
+ super(options.merge h)
2622
+
2623
+ end
2624
+
2625
+ def to_s()
2626
+ 'End If'
2627
+ end
2628
+
2629
+ end
2195
2630
 
2196
2631
  class ConnectivityAction < Action
2197
2632
 
@@ -2446,6 +2881,10 @@ class SpeakTextAction < DeviceAction
2446
2881
  super(options.merge h)
2447
2882
 
2448
2883
  end
2884
+
2885
+ def to_s()
2886
+ "Speak Text (%s)" % @h[:text_to_say]
2887
+ end
2449
2888
 
2450
2889
  end
2451
2890
 
@@ -2560,6 +2999,17 @@ class VibrateAction < DeviceSettingsAction
2560
2999
  super(options.merge h)
2561
3000
 
2562
3001
  end
3002
+
3003
+ def to_s()
3004
+
3005
+ pattern = [
3006
+ 'Blip', 'Short Buzz', 'Long Buzz', 'Rapid', 'Slow', 'Increasing',
3007
+ 'Constant', 'Decreasing', 'Final Fantasy', 'Game Over', 'Star Wars',
3008
+ 'Mini Blip', 'Micro Blip'
3009
+ ]
3010
+
3011
+ 'Vibrate ' + "(%s)" % pattern[@h[:vibrate_pattern].to_i]
3012
+ end
2563
3013
 
2564
3014
  end
2565
3015
 
@@ -3347,6 +3797,10 @@ end
3347
3797
 
3348
3798
  # Category: Screen
3349
3799
  #
3800
+ # options:
3801
+ # keep awake, screen on => enabled: true
3802
+ # disable keep awake => enabled: false
3803
+ #
3350
3804
  class KeepAwakeAction < ScreenAction
3351
3805
 
3352
3806
  def initialize(h={})
@@ -3361,7 +3815,30 @@ class KeepAwakeAction < ScreenAction
3361
3815
  super(options.merge h)
3362
3816
 
3363
3817
  end
3364
-
3818
+
3819
+ def to_s()
3820
+
3821
+ screen = @h[:screen_option] == 0 ? 'Screen On' : 'Screen Off'
3822
+
3823
+ if @h[:enabled] then
3824
+
3825
+ whenx = if @h[:seconds_to_stay_awake_for] == 0 then
3826
+
3827
+ 'Until Disabled'
3828
+
3829
+ else
3830
+ scnds = @h[:seconds_to_stay_awake_for]
3831
+ Subunit.new(units={minutes:60, hours:60}, seconds: scnds).strfunit("%x")
3832
+ end
3833
+
3834
+ 'Keep Device Awake ' + screen + ' ' + whenx
3835
+
3836
+ else
3837
+ 'Disable Keep Awake'
3838
+ end
3839
+
3840
+
3841
+ end
3365
3842
  end
3366
3843
 
3367
3844
  # Category: Screen
@@ -3542,6 +4019,21 @@ class BatteryLevelConstraint < Constraint
3542
4019
  super(options.merge h)
3543
4020
 
3544
4021
  end
4022
+
4023
+ def to_s()
4024
+
4025
+ operator = if @h[:greater_than] then
4026
+ '>'
4027
+ elsif @h[:equals]
4028
+ '='
4029
+ else
4030
+ '<'
4031
+ end
4032
+
4033
+ level = @h[:battery_level]
4034
+
4035
+ "Battery %s %s%%" % [operator, level]
4036
+ end
3545
4037
 
3546
4038
  end
3547
4039
 
@@ -3593,6 +4085,11 @@ class ExternalPowerConstraint < Constraint
3593
4085
  super(options.merge h)
3594
4086
 
3595
4087
  end
4088
+
4089
+ def to_s()
4090
+ connection = @h[:external_power] ? 'Connected' : 'Disconnected'
4091
+ 'Power ' + connection
4092
+ end
3596
4093
 
3597
4094
  end
3598
4095
 
@@ -3611,6 +4108,12 @@ class BluetoothConstraint < Constraint
3611
4108
  super(options.merge h)
3612
4109
 
3613
4110
  end
4111
+
4112
+ def to_s()
4113
+ device = @h[:device_name] #== 'Any Device' ? 'Any' : @h[:device_name]
4114
+ "Device Connected (%s)" % device
4115
+ end
4116
+
3614
4117
 
3615
4118
  end
3616
4119
 
@@ -3935,6 +4438,10 @@ class DeviceLockedConstraint < Constraint
3935
4438
  super(options.merge h)
3936
4439
 
3937
4440
  end
4441
+
4442
+ def to_s()
4443
+ 'Device ' + (@h[:locked] ? 'Locked' : 'Unlocked')
4444
+ end
3938
4445
 
3939
4446
  end
3940
4447
 
@@ -4121,6 +4628,11 @@ class HeadphonesConnectionConstraint < Constraint
4121
4628
  super(options.merge h)
4122
4629
 
4123
4630
  end
4631
+
4632
+ def to_s()
4633
+ connection = @h[:connected] ? 'Connected' : 'Disconnected'
4634
+ 'Headphones ' + connection
4635
+ end
4124
4636
 
4125
4637
  end
4126
4638
 
@@ -4310,6 +4822,10 @@ class ScreenOnOffConstraint < Constraint
4310
4822
  super(options.merge h)
4311
4823
 
4312
4824
  end
4825
+
4826
+ def to_s()
4827
+ 'Screen ' + (@h[:screen_on] ? 'On' : 'Off')
4828
+ end
4313
4829
 
4314
4830
  end
4315
4831
 
@@ -4363,6 +4879,14 @@ class LightLevelConstraint < Constraint
4363
4879
  super(options.merge h)
4364
4880
 
4365
4881
  end
4882
+
4883
+ def to_s()
4884
+
4885
+ operator = @h[:light_level] == -1 ? 'Less than' : 'Greater than'
4886
+ condition = operator + ' ' + @h[:light_level_float].to_s + 'lx'
4887
+ 'Light Sensor ' + condition
4888
+
4889
+ end
4366
4890
 
4367
4891
  end
4368
4892
 
@@ -4395,5 +4919,9 @@ class ProximitySensorConstraint < Constraint
4395
4919
  super(options.merge h)
4396
4920
 
4397
4921
  end
4922
+
4923
+ def to_s()
4924
+ 'Proximity Sensor: ' + (@h[:near] ? 'Near' : 'Far')
4925
+ end
4398
4926
 
4399
4927
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-macrodroid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -35,8 +35,28 @@ cert_chain:
35
35
  NZ2kdBIUDnAM24e0/wXdVxg4HnsZbdymxyzMQ4P5pKYcpI6oisBxI37p/Xy+wAg3
36
36
  SBHno3GEuuD8ZWj24IMJpfbp
37
37
  -----END CERTIFICATE-----
38
- date: 2020-09-04 00:00:00.000000000 Z
38
+ date: 2020-09-08 00:00:00.000000000 Z
39
39
  dependencies:
40
+ - !ruby/object:Gem::Dependency
41
+ name: glw
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.2'
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 0.2.2
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '0.2'
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 0.2.2
40
60
  - !ruby/object:Gem::Dependency
41
61
  name: uuid
42
62
  requirement: !ruby/object:Gem::Requirement
@@ -58,25 +78,45 @@ dependencies:
58
78
  - !ruby/object:Gem::Version
59
79
  version: 2.3.9
60
80
  - !ruby/object:Gem::Dependency
61
- name: glw
81
+ name: rowx
62
82
  requirement: !ruby/object:Gem::Requirement
63
83
  requirements:
64
- - - "~>"
65
- - !ruby/object:Gem::Version
66
- version: '0.2'
67
84
  - - ">="
68
85
  - !ruby/object:Gem::Version
69
- version: 0.2.2
86
+ version: 0.7.0
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.7'
70
90
  type: :runtime
71
91
  prerelease: false
72
92
  version_requirements: !ruby/object:Gem::Requirement
73
93
  requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 0.7.0
74
97
  - - "~>"
75
98
  - !ruby/object:Gem::Version
76
- version: '0.2'
99
+ version: '0.7'
100
+ - !ruby/object:Gem::Dependency
101
+ name: subunit
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
77
104
  - - ">="
78
105
  - !ruby/object:Gem::Version
79
- version: 0.2.2
106
+ version: 0.6.0
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.6'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 0.6.0
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '0.6'
80
120
  - !ruby/object:Gem::Dependency
81
121
  name: geozone
82
122
  requirement: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file