ruby-macrodroid 0.5.1 → 0.7.2
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/ruby-macrodroid.rb +831 -87
- metadata +84 -4
- metadata.gz.sig +1 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70dd1172a7d2ad827ff72771851910b140616b3f41fd7843ef65dc5bdf55fd5e
|
4
|
+
data.tar.gz: d5ef7e748dd16bfbc83e0ca05932a2b7723c61ea2ee2fbc8f69ef1c77c651ef0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91746fa312b8c1c5069c16f5c7337b1f6f438af8afecedc5e6469f21e00f98108788f3248d8d93284d9829858b0bf11ce5ad1591bba4a7f8f4ed1005a71c111c
|
7
|
+
data.tar.gz: bd1cefc341fd57809b563f1a4f21f013b3fe3e93143cef0c07862bdfe738ca6479e39c86a80355c110bd786da5b63849cc59616c7d67be58750c4ff2c68a47c3
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/ruby-macrodroid.rb
CHANGED
@@ -2,7 +2,117 @@
|
|
2
2
|
|
3
3
|
# file: ruby-macrodroid.rb
|
4
4
|
|
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
|
+
|
110
|
+
require 'yaml'
|
111
|
+
require 'rowx'
|
5
112
|
require 'uuid'
|
113
|
+
#require 'glw'
|
114
|
+
#require 'geozone'
|
115
|
+
require 'subunit'
|
6
116
|
require 'rxfhelper'
|
7
117
|
require 'chronic_cron'
|
8
118
|
|
@@ -30,7 +140,55 @@ class TriggersNlp
|
|
30
140
|
[TimerTrigger, {time: time, days: days}]
|
31
141
|
end
|
32
142
|
|
143
|
+
# time.is? 'at 18:30pm on Mon or Tue'
|
144
|
+
get /^time.is\? ['"](?:at )?(\d+:\d+(?:[ap]m)?) (?:on )?(.*)['"]/i do |time, days|
|
145
|
+
[TimerTrigger, {time: time, days: days.gsub(' or ',', ')}]
|
146
|
+
end
|
147
|
+
|
148
|
+
get /^shake[ _]device\??$/i do
|
149
|
+
[ShakeDeviceTrigger, {}]
|
150
|
+
end
|
151
|
+
|
152
|
+
get /^Flip Device (.*)$/i do |motion|
|
153
|
+
facedown = motion =~ /Face Up (?:->|to) Face Down/i
|
154
|
+
[FlipDeviceTrigger, {face_down: facedown }]
|
155
|
+
end
|
156
|
+
|
157
|
+
get /^flip_device_down\?$/i do
|
158
|
+
[FlipDeviceTrigger, {face_down: true }]
|
159
|
+
end
|
160
|
+
|
161
|
+
get /^flip_device_up\?$/i do
|
162
|
+
[FlipDeviceTrigger, {face_down: false }]
|
163
|
+
end
|
164
|
+
|
165
|
+
get /^Failed Login Attempt$/i do
|
166
|
+
[FailedLoginTrigger, {}]
|
167
|
+
end
|
168
|
+
|
169
|
+
get /^failed_login?$/i do
|
170
|
+
[FailedLoginTrigger, {}]
|
171
|
+
end
|
172
|
+
|
173
|
+
get /^Geofence (Entry|Exit) \(([^\)]+)/i do |direction, name|
|
174
|
+
enter_area = direction.downcase.to_sym == :entry
|
175
|
+
[GeofenceTrigger, {name: name, enter_area: enter_area}]
|
176
|
+
end
|
177
|
+
|
178
|
+
get /^location (entered|exited) \(([^\)]+)/i do |direction, name|
|
179
|
+
enter_area = direction.downcase.to_sym == :entered
|
180
|
+
[GeofenceTrigger, {name: name, enter_area: enter_area}]
|
181
|
+
end
|
182
|
+
|
183
|
+
# eg. Proximity Sensor (Near)
|
184
|
+
#
|
185
|
+
get /^Proximity Sensor \(([^\)]+)\)/i do |distance|
|
186
|
+
|
187
|
+
[ProximityTrigger, {distance: distance}]
|
188
|
+
end
|
33
189
|
|
190
|
+
|
191
|
+
|
34
192
|
end
|
35
193
|
|
36
194
|
alias find_trigger run_route
|
@@ -50,13 +208,105 @@ class ActionsNlp
|
|
50
208
|
|
51
209
|
def actions(params)
|
52
210
|
|
211
|
+
# e.g. message popup: hello world!
|
53
212
|
get /^message popup: (.*)/i do |msg|
|
54
213
|
[ToastAction, {msg: msg}]
|
55
214
|
end
|
56
215
|
|
57
|
-
|
216
|
+
# e.g. Popup Message 'hello world!'
|
217
|
+
get /^Popup[ _]Message ['"]([^'"]+)/i do |msg|
|
58
218
|
[ToastAction, {msg: msg}]
|
59
219
|
end
|
220
|
+
|
221
|
+
# e.g. say current time
|
222
|
+
get /^say current[ _]time/i do
|
223
|
+
[SayTimeAction, {}]
|
224
|
+
end
|
225
|
+
|
226
|
+
get /^Torch :?(.*)/i do |onoffstate|
|
227
|
+
state = onoffstate.downcase == 'on' ? 0 : 1
|
228
|
+
[CameraFlashLightAction, {state: state}]
|
229
|
+
end
|
230
|
+
|
231
|
+
get /^Take Picture/i do
|
232
|
+
[TakePictureAction, {}]
|
233
|
+
end
|
234
|
+
|
235
|
+
get /^take_picture/i do
|
236
|
+
[TakePictureAction, {}]
|
237
|
+
end
|
238
|
+
|
239
|
+
# e.g. Display Notification: Hi there: This is the body of the message
|
240
|
+
get /^Display Notification: ([^:]+): [^$]+$/i do |subject, text|
|
241
|
+
[NotificationAction, {subject: subject, text: text}]
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
# e.g. Enable Wifi
|
246
|
+
get /^(Enable|Disable) Wifi$/i do |raw_state|
|
247
|
+
|
248
|
+
state = raw_state.downcase.to_sym == :enable ? 0 : 1
|
249
|
+
[SetWifiAction, {state: state}]
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
# e.g. Play: Altair
|
254
|
+
get /^Play: (.*)$/i do |name|
|
255
|
+
|
256
|
+
[PlaySoundAction, {file_path: name}]
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
# e.g. Launch Settings
|
261
|
+
get /^Launch (.*)$/i do |application|
|
262
|
+
|
263
|
+
h = {
|
264
|
+
application_name: application,
|
265
|
+
package_to_launch: 'com.android.' + application.downcase
|
266
|
+
}
|
267
|
+
[LaunchActivityAction, h]
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
# e.g. HTTP GET http://someurl.com/something
|
272
|
+
get /^HTTP GET ([^$]+)$/i do |url|
|
273
|
+
|
274
|
+
[OpenWebPageAction, url_to_open: url]
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
# e.g. webhook entered_kitchen
|
279
|
+
#
|
280
|
+
get /webhook|HTTP GET/i do
|
281
|
+
[OpenWebPageAction, {}]
|
282
|
+
end
|
283
|
+
|
284
|
+
#a: Keep Device Awake Screen On Until Disabled
|
285
|
+
#
|
286
|
+
get /Keep Device Awake Screen On Until Disabled/i do
|
287
|
+
[KeepAwakeAction, {enabled: true, permanent: true, screen_option: 0}]
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
#a: Keep Device Awake Screen On 1h 1m 1s
|
292
|
+
#
|
293
|
+
get /Keep Device Awake Screen On ([^$]+)/i do |duration|
|
294
|
+
|
295
|
+
a = duration.split.map(&:to_i)
|
296
|
+
secs = Subunit.new(units={minutes:60, hours:60, seconds: 60}, a).to_i
|
297
|
+
|
298
|
+
h = {
|
299
|
+
permanent: true, screen_option: 0, seconds_to_stay_awake_for: secs
|
300
|
+
}
|
301
|
+
[KeepAwakeAction, h]
|
302
|
+
end
|
303
|
+
|
304
|
+
#a: Disable Keep Awake
|
305
|
+
#
|
306
|
+
get /Disable Keep Awake/i do
|
307
|
+
[KeepAwakeAction, {enabled: false, screen_option: 0}]
|
308
|
+
end
|
309
|
+
|
60
310
|
|
61
311
|
end
|
62
312
|
|
@@ -145,11 +395,11 @@ class Macro
|
|
145
395
|
using Params
|
146
396
|
|
147
397
|
attr_reader :local_variables, :triggers, :actions, :constraints, :guid
|
148
|
-
attr_accessor :title
|
398
|
+
attr_accessor :title, :description
|
149
399
|
|
150
|
-
def initialize(name=nil, debug: false)
|
400
|
+
def initialize(name=nil, geofences: geofences, debug: false)
|
151
401
|
|
152
|
-
@title, @debug = name, debug
|
402
|
+
@title, @geofences, @debug = name, geofences, debug
|
153
403
|
|
154
404
|
puts 'inside Macro#initialize' if @debug
|
155
405
|
|
@@ -209,6 +459,7 @@ class Macro
|
|
209
459
|
end
|
210
460
|
|
211
461
|
@title = h[:name]
|
462
|
+
@description = h[:description]
|
212
463
|
|
213
464
|
# fetch the local variables
|
214
465
|
@local_variables = h['local_variables']
|
@@ -239,18 +490,20 @@ class Macro
|
|
239
490
|
end
|
240
491
|
|
241
492
|
def import_xml(node)
|
242
|
-
|
493
|
+
|
243
494
|
if @debug then
|
244
495
|
puts 'inside Macro#import_xml'
|
245
496
|
puts 'node: ' + node.xml.inspect
|
246
497
|
end
|
247
498
|
|
248
|
-
@title = node.attributes[:name]
|
249
|
-
|
250
499
|
if node.element('triggers') then
|
251
|
-
|
500
|
+
|
252
501
|
# level 2
|
253
502
|
|
503
|
+
@title = node.attributes[:name]
|
504
|
+
@description = node.attributes[:description]
|
505
|
+
|
506
|
+
|
254
507
|
# get all the triggers
|
255
508
|
@triggers = node.xpath('triggers/*').map do |e|
|
256
509
|
|
@@ -286,6 +539,12 @@ class Macro
|
|
286
539
|
|
287
540
|
# Level 1
|
288
541
|
|
542
|
+
puts 'import_xml: inside level 1' if @debug
|
543
|
+
|
544
|
+
@title = node.text('macro') || node.attributes[:name]
|
545
|
+
|
546
|
+
#@description = node.attributes[:description]
|
547
|
+
|
289
548
|
tp = TriggersNlp.new
|
290
549
|
|
291
550
|
@triggers = node.xpath('trigger').map do |e|
|
@@ -295,7 +554,11 @@ class Macro
|
|
295
554
|
puts 'found trigger ' + r.inspect if @debug
|
296
555
|
|
297
556
|
if r then
|
298
|
-
r[0]
|
557
|
+
if r[0] == GeofenceTrigger then
|
558
|
+
GeofenceTrigger.new(r[1], geofences: @geofences)
|
559
|
+
else
|
560
|
+
r[0].new(r[1])
|
561
|
+
end
|
299
562
|
end
|
300
563
|
|
301
564
|
end
|
@@ -304,11 +567,21 @@ class Macro
|
|
304
567
|
|
305
568
|
@actions = node.xpath('action').map do |e|
|
306
569
|
|
570
|
+
puts 'action e: ' + e.xml.inspect if @debug
|
307
571
|
r = ap.find_action e.text
|
308
572
|
puts 'found action ' + r.inspect if @debug
|
309
573
|
|
310
574
|
if r then
|
311
|
-
|
575
|
+
|
576
|
+
a = e.xpath('item/*')
|
577
|
+
|
578
|
+
h = if a.any? then
|
579
|
+
a.map {|node| [node.name.to_sym, node.text.to_s]}.to_h
|
580
|
+
else
|
581
|
+
{}
|
582
|
+
end
|
583
|
+
|
584
|
+
r[0].new(r[1].merge(h))
|
312
585
|
end
|
313
586
|
|
314
587
|
end
|
@@ -355,17 +628,64 @@ class Macro
|
|
355
628
|
|
356
629
|
end
|
357
630
|
|
631
|
+
# invokes the actions
|
632
|
+
#
|
358
633
|
def run()
|
359
634
|
@actions.map(&:invoke)
|
360
|
-
end
|
635
|
+
end
|
636
|
+
|
637
|
+
# prepares the environment in order for triggers to test fire successfully
|
638
|
+
# Used for testing
|
639
|
+
#
|
640
|
+
def set_env()
|
641
|
+
@triggers.each(&:set_env)
|
642
|
+
end
|
643
|
+
|
644
|
+
def to_pc()
|
645
|
+
|
646
|
+
heading = '# ' + @title
|
647
|
+
heading += '\n# ' + @description if @description
|
648
|
+
condition = @triggers.first.to_pc
|
649
|
+
actions = @actions.map(&:to_pc).join("\n")
|
650
|
+
|
651
|
+
<<EOF
|
652
|
+
#{heading}
|
653
|
+
|
654
|
+
if #{condition} then
|
655
|
+
#{actions}
|
656
|
+
end
|
657
|
+
EOF
|
658
|
+
end
|
361
659
|
|
362
660
|
def to_s()
|
363
|
-
|
661
|
+
|
662
|
+
a = [
|
364
663
|
'm: ' + @title,
|
365
664
|
@triggers.map {|x| "t: %s" % x}.join("\n"),
|
366
665
|
@actions.map {|x| "a: %s" % x}.join("\n"),
|
367
666
|
@constraints.map {|x| "a: %s" % x}.join("\n")
|
368
|
-
]
|
667
|
+
]
|
668
|
+
|
669
|
+
if @description and @description.length >= 1 then
|
670
|
+
a.insert(1, 'd: ' + @description)
|
671
|
+
end
|
672
|
+
|
673
|
+
a.join("\n")
|
674
|
+
|
675
|
+
end
|
676
|
+
|
677
|
+
def to_summary()
|
678
|
+
|
679
|
+
a = [
|
680
|
+
'm: ' + @title,
|
681
|
+
't: ' + @triggers.map(&:to_summary).join(", "),
|
682
|
+
'a: ' + @actions.map(&:to_summary).join(", "),
|
683
|
+
]
|
684
|
+
|
685
|
+
a << 'c: ' + @constraints.map(&:to_summary).join(", ") if @constraints.any?
|
686
|
+
|
687
|
+
a.join("\n") + "\n"
|
688
|
+
|
369
689
|
end
|
370
690
|
|
371
691
|
private
|
@@ -378,34 +698,86 @@ class Macro
|
|
378
698
|
|
379
699
|
puts ('inside object h:' + h.inspect).debug if @debug
|
380
700
|
klass = Object.const_get h[:class_type]
|
381
|
-
klass.
|
701
|
+
puts klass.inspect.highlight if $debug
|
702
|
+
|
703
|
+
if klass == GeofenceTrigger then
|
704
|
+
puts 'GeofenceTrigger found'.highlight if $debug
|
705
|
+
GeofenceTrigger.new(h, geofences: @geofences)
|
706
|
+
else
|
707
|
+
klass.new h
|
708
|
+
end
|
709
|
+
|
382
710
|
end
|
383
711
|
|
384
712
|
end
|
385
713
|
|
386
714
|
|
715
|
+
class MacroDroidError < Exception
|
716
|
+
end
|
717
|
+
|
387
718
|
class MacroDroid
|
388
719
|
using ColouredText
|
389
720
|
using Params
|
390
721
|
|
391
|
-
attr_reader :macros
|
722
|
+
attr_reader :macros, :geofences
|
392
723
|
|
393
724
|
def initialize(obj=nil, debug: false)
|
394
725
|
|
395
726
|
@debug = debug
|
396
727
|
|
728
|
+
@geofences = {}
|
729
|
+
|
397
730
|
if obj then
|
398
731
|
|
399
|
-
|
732
|
+
raw_s, _ = RXFHelper.read(obj)
|
733
|
+
|
734
|
+
s = raw_s.strip
|
400
735
|
|
401
736
|
if s[0] == '{' then
|
737
|
+
|
402
738
|
import_json(s)
|
739
|
+
|
403
740
|
elsif s[0] == '<'
|
741
|
+
|
404
742
|
import_xml(s)
|
405
743
|
@h = build_h
|
744
|
+
|
406
745
|
else
|
407
|
-
|
746
|
+
|
747
|
+
puts 's: ' + s.inspect if @debug
|
748
|
+
|
749
|
+
if s =~ /m(?:acro)?:\s/ then
|
750
|
+
|
751
|
+
puts 'before RowX.new' if @debug
|
752
|
+
|
753
|
+
s2 = s.gsub(/^g:/,'geofence:').gsub(/^m:/,'macro:')\
|
754
|
+
.gsub(/^t:/,'trigger:').gsub(/^a:/,'action:')\
|
755
|
+
.gsub(/^c:/,'constraint:').gsub(/^#.*/,'')
|
756
|
+
|
757
|
+
raw_macros, raw_geofences = s2.split(/(?=^macro:)/,2).reverse
|
758
|
+
|
759
|
+
if raw_geofences then
|
760
|
+
|
761
|
+
geoxml = RowX.new(raw_geofences).to_xml
|
762
|
+
|
763
|
+
geodoc = Rexle.new(geoxml)
|
764
|
+
geofences = geodoc.root.xpath('item/geofence')
|
765
|
+
@geofences = fetch_geofences(geofences) if geofences.any?
|
766
|
+
|
767
|
+
end
|
768
|
+
|
769
|
+
xml = RowX.new(raw_macros).to_xml
|
770
|
+
import_rowxml(xml)
|
771
|
+
|
772
|
+
elsif s =~ /^# /
|
773
|
+
xml = pc_to_xml(s)
|
774
|
+
import_xml(xml)
|
775
|
+
else
|
776
|
+
raise MacroDroidError, 'invalid input'
|
777
|
+
end
|
778
|
+
|
408
779
|
@h = build_h
|
780
|
+
|
409
781
|
end
|
410
782
|
|
411
783
|
else
|
@@ -457,15 +829,94 @@ class MacroDroid
|
|
457
829
|
|
458
830
|
alias to_json export_json
|
459
831
|
|
832
|
+
|
833
|
+
def to_h()
|
834
|
+
|
835
|
+
h = {
|
836
|
+
geofence_data: {
|
837
|
+
geofence_map: @geofences.map {|key, value| [key, value.to_h] }.to_h
|
838
|
+
},
|
839
|
+
macro_list: @macros.map(&:to_h)
|
840
|
+
}
|
841
|
+
@h.merge(h).to_camel_case
|
842
|
+
|
843
|
+
end
|
844
|
+
|
845
|
+
# returns pseudocode
|
846
|
+
#
|
847
|
+
def to_pc()
|
848
|
+
@macros.map(&:to_pc).join("\n\n")
|
849
|
+
end
|
850
|
+
|
851
|
+
def to_s()
|
852
|
+
|
853
|
+
lines = []
|
854
|
+
|
855
|
+
if @geofences.any? then
|
856
|
+
lines << @geofences.map {|_, value| 'g: ' + value.to_s}.join("\n\n") + "\n"
|
857
|
+
end
|
858
|
+
|
859
|
+
lines << @macros.map(&:to_s).join("\n")
|
860
|
+
lines.join("\n")
|
861
|
+
|
862
|
+
end
|
863
|
+
|
864
|
+
def to_summary()
|
865
|
+
@macros.map(&:to_summary).join("\n")
|
866
|
+
end
|
867
|
+
|
868
|
+
private
|
869
|
+
|
870
|
+
def fetch_geofences(nodes)
|
871
|
+
|
872
|
+
nodes.map do |e|
|
873
|
+
|
874
|
+
name = e.text.to_s.strip
|
875
|
+
item = e.element('item')
|
876
|
+
coordinates = item.text('coordinates')
|
877
|
+
latitude, longitude = coordinates.split(/, */,2)
|
878
|
+
radius = item.text('radius')
|
879
|
+
|
880
|
+
id = UUID.new.generate
|
881
|
+
|
882
|
+
h = {
|
883
|
+
name: name,
|
884
|
+
longitude: longitude,
|
885
|
+
latitude: latitude,
|
886
|
+
radius: radius,
|
887
|
+
id: id
|
888
|
+
}
|
889
|
+
|
890
|
+
[id.to_sym, GeofenceMap.new(h)]
|
891
|
+
|
892
|
+
end.to_h
|
893
|
+
|
894
|
+
end
|
895
|
+
|
460
896
|
def import_json(s)
|
461
897
|
|
462
|
-
|
898
|
+
h = JSON.parse(s, symbolize_names: true)
|
899
|
+
puts 'json_to_yaml: ' + h.to_yaml if @debug
|
900
|
+
|
901
|
+
@h = h.to_snake_case
|
463
902
|
puts ('@h: ' + @h.inspect).debug if @debug
|
464
|
-
|
903
|
+
|
904
|
+
|
905
|
+
# fetch the geofence data
|
906
|
+
if @h[:geofence_data] then
|
907
|
+
|
908
|
+
@geofences = @h[:geofence_data][:geofence_map].map do |id, properties|
|
909
|
+
[id, GeofenceMap.new(properties)]
|
910
|
+
end.to_h
|
911
|
+
|
912
|
+
end
|
913
|
+
|
465
914
|
@macros = @h[:macro_list].map do |macro|
|
466
915
|
|
467
916
|
puts ('macro: ' + macro.inspect).debug if @debug
|
468
|
-
|
917
|
+
# puts '@geofences: ' + @geofences.inspect if @debug
|
918
|
+
|
919
|
+
m = Macro.new(geofences: @geofences.map(&:last), debug: @debug )
|
469
920
|
m.import_h(macro)
|
470
921
|
m
|
471
922
|
|
@@ -475,59 +926,99 @@ class MacroDroid
|
|
475
926
|
|
476
927
|
end
|
477
928
|
|
929
|
+
def import_rowxml(raws)
|
930
|
+
|
931
|
+
s = RXFHelper.read(raws).first
|
932
|
+
puts 's: ' + s.inspect if @debug
|
933
|
+
doc = Rexle.new(s)
|
934
|
+
puts 'after doc' if @debug
|
935
|
+
puts 'import_rowxml: @geofences: ' + @geofences.inspect if @debug
|
936
|
+
geofences = @geofences
|
937
|
+
|
938
|
+
@macros = doc.root.xpath('item').map do |node|
|
939
|
+
puts ('geofences: ' + geofences.inspect).highlight if @debug
|
940
|
+
Macro.new(geofences: geofences.map(&:last), debug: @debug).import_xml(node)
|
941
|
+
|
942
|
+
end
|
943
|
+
|
944
|
+
end
|
945
|
+
|
478
946
|
def import_xml(raws)
|
479
947
|
|
948
|
+
if @debug then
|
949
|
+
puts 'inside import_xml'
|
950
|
+
|
951
|
+
puts 'raws: ' + raws.inspect
|
952
|
+
end
|
480
953
|
s = RXFHelper.read(raws).first
|
481
954
|
puts 's: ' + s.inspect if @debug
|
482
955
|
doc = Rexle.new(s)
|
483
|
-
puts 'after doc' if @debug
|
484
956
|
|
957
|
+
if @debug then
|
958
|
+
puts 'doc: ' + doc.root.xml
|
959
|
+
end
|
960
|
+
|
485
961
|
@macros = doc.root.xpath('macro').map do |node|
|
486
962
|
|
487
|
-
|
488
|
-
macro.import_xml(node)
|
489
|
-
macro
|
963
|
+
Macro.new(geofences: @geofences.map(&:last), debug: @debug).import_xml(node)
|
490
964
|
|
491
965
|
end
|
492
966
|
end
|
493
967
|
|
494
|
-
def
|
968
|
+
def pc_to_xml(s)
|
495
969
|
|
496
|
-
|
497
|
-
a.map!(&:chomp)
|
498
|
-
|
499
|
-
macros = a.map do |x|
|
500
|
-
|
501
|
-
lines = x.lines
|
502
|
-
puts 'lines: ' + lines.inspect if @debug
|
503
|
-
|
504
|
-
name = lines.shift[/^m: +(.*)/,1]
|
505
|
-
h = {t: [], a: [], c: []}
|
970
|
+
macros = s.strip.split(/(?=#)/).map do |raw_macro|
|
506
971
|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
972
|
+
a = raw_macro.lines
|
973
|
+
name = a.shift[/(?<=# ).*/]
|
974
|
+
description = a.shift[/(?<=# ).*/] if a[0][/^# /]
|
975
|
+
body = a.join.strip
|
511
976
|
|
512
|
-
|
977
|
+
a2 = body.lines
|
978
|
+
# get the trigger
|
979
|
+
trigger = [:trigger, {}, a2[0][/^if (.*) then/,1]]
|
980
|
+
action = [:action, {}, a2[1].strip]
|
981
|
+
[:macro, {name: name, description: description}, trigger, action, []]
|
513
982
|
|
514
983
|
end
|
515
984
|
|
516
985
|
doc = Rexle.new([:macros, {}, '', *macros])
|
517
986
|
doc.root.xml pretty: true
|
518
987
|
|
519
|
-
end
|
520
|
-
|
521
|
-
def to_h()
|
988
|
+
end
|
522
989
|
|
523
|
-
|
990
|
+
end
|
524
991
|
|
992
|
+
class GeofenceMap
|
993
|
+
|
994
|
+
attr_accessor :name, :longitude, :latitude, :radius, :id
|
995
|
+
|
996
|
+
def initialize(id: '', longitude: '', latitude: '', name: '', radius: '')
|
997
|
+
|
998
|
+
@id, @latitude, @longitude, @name, @radius = id, latitude, \
|
999
|
+
longitude, name, radius
|
1000
|
+
|
525
1001
|
end
|
526
|
-
|
1002
|
+
|
1003
|
+
def to_h()
|
1004
|
+
|
1005
|
+
{
|
1006
|
+
id: @id,
|
1007
|
+
longitude: @longitude,
|
1008
|
+
latitude: @latitude,
|
1009
|
+
name: @name,
|
1010
|
+
radius: @radius
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
end
|
1014
|
+
|
527
1015
|
def to_s()
|
528
|
-
|
1016
|
+
|
1017
|
+
coordinates = "%s, %s" % [@longitude, @latitude]
|
1018
|
+
"%s\n coordinates: %s\n radius: %s" % [@name, coordinates, @radius]
|
1019
|
+
|
529
1020
|
end
|
530
|
-
|
1021
|
+
|
531
1022
|
end
|
532
1023
|
|
533
1024
|
class MacroObject
|
@@ -538,6 +1029,8 @@ class MacroObject
|
|
538
1029
|
|
539
1030
|
def initialize(h={})
|
540
1031
|
|
1032
|
+
$env ||= {}
|
1033
|
+
|
541
1034
|
@h = {constraint_list: [], is_or_condition: false,
|
542
1035
|
is_disabled: false}.merge(h)
|
543
1036
|
@list = []
|
@@ -566,6 +1059,12 @@ class MacroObject
|
|
566
1059
|
h2.merge('m_classType' => self.class.to_s)
|
567
1060
|
|
568
1061
|
end
|
1062
|
+
|
1063
|
+
def to_s()
|
1064
|
+
"#<%s %s>" % [self.class, @h.inspect]
|
1065
|
+
end
|
1066
|
+
|
1067
|
+
alias to_summary to_s
|
569
1068
|
|
570
1069
|
protected
|
571
1070
|
|
@@ -1080,29 +1579,26 @@ class TimerTrigger < Trigger
|
|
1080
1579
|
use_alarm: false
|
1081
1580
|
}
|
1082
1581
|
|
1083
|
-
super(options.merge filter(options,h))
|
1582
|
+
super(options.merge filter(options, h))
|
1084
1583
|
|
1085
1584
|
end
|
1086
1585
|
|
1087
1586
|
def match?(detail={time: $env[:time]}, model=nil)
|
1088
|
-
|
1089
|
-
a = @h[:days_of_week]
|
1090
|
-
a.unshift a.pop
|
1091
|
-
|
1092
|
-
dow = a.map.with_index {|x, i| x ? i : nil }.compact.join(',')
|
1093
|
-
|
1094
|
-
s = "%s %s * * %s" % [@h[:minute], @h[:hour], dow]
|
1095
|
-
|
1096
|
-
if $debug then
|
1097
|
-
puts 's: ' + s.inspect
|
1098
|
-
puts 'detail: ' + detail.inspect
|
1099
|
-
puts '@h: ' + @h.inspect
|
1100
|
-
end
|
1101
1587
|
|
1102
|
-
|
1588
|
+
time() == detail[:time]
|
1103
1589
|
|
1104
1590
|
end
|
1105
1591
|
|
1592
|
+
# sets the environmental conditions for this trigger to fire
|
1593
|
+
#
|
1594
|
+
def set_env()
|
1595
|
+
$env[:time] = time()
|
1596
|
+
end
|
1597
|
+
|
1598
|
+
def to_pc()
|
1599
|
+
"time.is? '%s'" % self.to_s.gsub(',', ' or')
|
1600
|
+
end
|
1601
|
+
|
1106
1602
|
def to_s()
|
1107
1603
|
|
1108
1604
|
dow = @h[:days_of_week]
|
@@ -1114,6 +1610,20 @@ class TimerTrigger < Trigger
|
|
1114
1610
|
|
1115
1611
|
"at %s on %s" % [time, days.join(', ')]
|
1116
1612
|
end
|
1613
|
+
|
1614
|
+
private
|
1615
|
+
|
1616
|
+
def time()
|
1617
|
+
|
1618
|
+
a = @h[:days_of_week].clone
|
1619
|
+
a.unshift a.pop
|
1620
|
+
|
1621
|
+
dow = a.map.with_index {|x, i| x ? i : nil }.compact.join(',')
|
1622
|
+
s = "%s %s * * %s" % [@h[:minute], @h[:hour], dow]
|
1623
|
+
recent_time = ($env && $env[:time]) ? $env[:time] : Time.now
|
1624
|
+
ChronicCron.new(s, recent_time).to_time
|
1625
|
+
|
1626
|
+
end
|
1117
1627
|
|
1118
1628
|
end
|
1119
1629
|
|
@@ -1185,6 +1695,15 @@ class RegularIntervalTrigger < Trigger
|
|
1185
1695
|
|
1186
1696
|
end
|
1187
1697
|
|
1698
|
+
class DeviceEventsTrigger < Trigger
|
1699
|
+
|
1700
|
+
def initialize(h={})
|
1701
|
+
super(h)
|
1702
|
+
@group = 'device_events'
|
1703
|
+
end
|
1704
|
+
|
1705
|
+
end
|
1706
|
+
|
1188
1707
|
# Category: Device Events
|
1189
1708
|
#
|
1190
1709
|
# Airplane Mode Changed
|
@@ -1196,7 +1715,7 @@ end
|
|
1196
1715
|
# shorthand example:
|
1197
1716
|
# airplanemode: enabled
|
1198
1717
|
#
|
1199
|
-
class AirplaneModeTrigger <
|
1718
|
+
class AirplaneModeTrigger < DeviceEventsTrigger
|
1200
1719
|
|
1201
1720
|
def initialize(h={})
|
1202
1721
|
|
@@ -1212,7 +1731,7 @@ end
|
|
1212
1731
|
|
1213
1732
|
# Category: Device Events
|
1214
1733
|
#
|
1215
|
-
class AutoSyncChangeTrigger <
|
1734
|
+
class AutoSyncChangeTrigger < DeviceEventsTrigger
|
1216
1735
|
|
1217
1736
|
def initialize(h={})
|
1218
1737
|
|
@@ -1228,7 +1747,7 @@ end
|
|
1228
1747
|
|
1229
1748
|
# Category: Device Events
|
1230
1749
|
#
|
1231
|
-
class DayDreamTrigger <
|
1750
|
+
class DayDreamTrigger < DeviceEventsTrigger
|
1232
1751
|
|
1233
1752
|
def initialize(h={})
|
1234
1753
|
|
@@ -1244,7 +1763,7 @@ end
|
|
1244
1763
|
|
1245
1764
|
# Category: Device Events
|
1246
1765
|
#
|
1247
|
-
class DockTrigger <
|
1766
|
+
class DockTrigger < DeviceEventsTrigger
|
1248
1767
|
|
1249
1768
|
def initialize(h={})
|
1250
1769
|
|
@@ -1260,7 +1779,30 @@ end
|
|
1260
1779
|
|
1261
1780
|
# Category: Device Events
|
1262
1781
|
#
|
1263
|
-
class
|
1782
|
+
class FailedLoginTrigger < DeviceEventsTrigger
|
1783
|
+
|
1784
|
+
def initialize(h={})
|
1785
|
+
|
1786
|
+
options = {
|
1787
|
+
num_failures: 1
|
1788
|
+
}
|
1789
|
+
|
1790
|
+
super(options.merge h)
|
1791
|
+
|
1792
|
+
end
|
1793
|
+
|
1794
|
+
def to_pc()
|
1795
|
+
'failed_login?'
|
1796
|
+
end
|
1797
|
+
|
1798
|
+
def to_s()
|
1799
|
+
'Failed Login Attempt'
|
1800
|
+
end
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
# Category: Device Events
|
1804
|
+
#
|
1805
|
+
class GPSEnabledTrigger < DeviceEventsTrigger
|
1264
1806
|
|
1265
1807
|
def initialize(h={})
|
1266
1808
|
|
@@ -1276,7 +1818,7 @@ end
|
|
1276
1818
|
|
1277
1819
|
# Category: Device Events
|
1278
1820
|
#
|
1279
|
-
class MusicPlayingTrigger <
|
1821
|
+
class MusicPlayingTrigger < DeviceEventsTrigger
|
1280
1822
|
|
1281
1823
|
def initialize(h={})
|
1282
1824
|
|
@@ -1293,7 +1835,7 @@ end
|
|
1293
1835
|
|
1294
1836
|
# Category: Device Events
|
1295
1837
|
#
|
1296
|
-
class DeviceUnlockedTrigger <
|
1838
|
+
class DeviceUnlockedTrigger < DeviceEventsTrigger
|
1297
1839
|
|
1298
1840
|
def initialize(h={})
|
1299
1841
|
|
@@ -1308,7 +1850,7 @@ end
|
|
1308
1850
|
|
1309
1851
|
# Category: Device Events
|
1310
1852
|
#
|
1311
|
-
class AutoRotateChangeTrigger <
|
1853
|
+
class AutoRotateChangeTrigger < DeviceEventsTrigger
|
1312
1854
|
|
1313
1855
|
def initialize(h={})
|
1314
1856
|
|
@@ -1324,7 +1866,7 @@ end
|
|
1324
1866
|
|
1325
1867
|
# Category: Device Events
|
1326
1868
|
#
|
1327
|
-
class ClipboardChangeTrigger <
|
1869
|
+
class ClipboardChangeTrigger < DeviceEventsTrigger
|
1328
1870
|
|
1329
1871
|
def initialize(h={})
|
1330
1872
|
|
@@ -1341,7 +1883,7 @@ end
|
|
1341
1883
|
|
1342
1884
|
# Category: Device Events
|
1343
1885
|
#
|
1344
|
-
class BootTrigger <
|
1886
|
+
class BootTrigger < DeviceEventsTrigger
|
1345
1887
|
|
1346
1888
|
def initialize(h={})
|
1347
1889
|
|
@@ -1356,7 +1898,7 @@ end
|
|
1356
1898
|
|
1357
1899
|
# Category: Device Events
|
1358
1900
|
#
|
1359
|
-
class IntentReceivedTrigger <
|
1901
|
+
class IntentReceivedTrigger < DeviceEventsTrigger
|
1360
1902
|
|
1361
1903
|
def initialize(h={})
|
1362
1904
|
|
@@ -1376,7 +1918,7 @@ end
|
|
1376
1918
|
|
1377
1919
|
# Category: Device Events
|
1378
1920
|
#
|
1379
|
-
class NotificationTrigger <
|
1921
|
+
class NotificationTrigger < DeviceEventsTrigger
|
1380
1922
|
|
1381
1923
|
def initialize(h={})
|
1382
1924
|
|
@@ -1402,7 +1944,7 @@ end
|
|
1402
1944
|
|
1403
1945
|
# Category: Device Events
|
1404
1946
|
#
|
1405
|
-
class ScreenOnOffTrigger <
|
1947
|
+
class ScreenOnOffTrigger < DeviceEventsTrigger
|
1406
1948
|
|
1407
1949
|
def initialize(h={})
|
1408
1950
|
|
@@ -1418,7 +1960,7 @@ end
|
|
1418
1960
|
|
1419
1961
|
# Category: Device Events
|
1420
1962
|
#
|
1421
|
-
class SilentModeTrigger <
|
1963
|
+
class SilentModeTrigger < DeviceEventsTrigger
|
1422
1964
|
|
1423
1965
|
def initialize(h={})
|
1424
1966
|
|
@@ -1461,8 +2003,15 @@ end
|
|
1461
2003
|
#
|
1462
2004
|
class GeofenceTrigger < Trigger
|
1463
2005
|
|
1464
|
-
def initialize(h={})
|
2006
|
+
def initialize( h={}, geofences: {})
|
1465
2007
|
|
2008
|
+
if h[:name] then
|
2009
|
+
puts ('geofences2: ' + geofences.inspect)
|
2010
|
+
found = geofences.find {|x| x.name.downcase == h[:name].downcase}
|
2011
|
+
h[:geofence_id] = found.id if found
|
2012
|
+
|
2013
|
+
end
|
2014
|
+
|
1466
2015
|
options = {
|
1467
2016
|
update_rate_text: '5 Minutes',
|
1468
2017
|
geofence_id: '',
|
@@ -1471,9 +2020,28 @@ class GeofenceTrigger < Trigger
|
|
1471
2020
|
enter_area: true
|
1472
2021
|
}
|
1473
2022
|
|
1474
|
-
super(options.merge h)
|
2023
|
+
super(options.merge filter(options, h))
|
2024
|
+
@geofences = geofences
|
1475
2025
|
|
1476
2026
|
end
|
2027
|
+
|
2028
|
+
def to_s()
|
2029
|
+
|
2030
|
+
if $debug then
|
2031
|
+
puts ' @geofences: ' + @geofences.inspect
|
2032
|
+
puts '@h: ' + @h.inspect
|
2033
|
+
puts '@h[:geofence_id]: ' + @h[:geofence_id].inspect
|
2034
|
+
end
|
2035
|
+
|
2036
|
+
direction = @h[:enter_area] ? 'Entry' : 'Exit'
|
2037
|
+
|
2038
|
+
found = @geofences.find {|x| x.id == @h[:geofence_id]}
|
2039
|
+
puts 'found: ' + found.inspect if @debug
|
2040
|
+
label = found ? found.name : 'error: name not found'
|
2041
|
+
|
2042
|
+
"Geofence %s (%s)" % [direction, label]
|
2043
|
+
|
2044
|
+
end
|
1477
2045
|
|
1478
2046
|
end
|
1479
2047
|
|
@@ -1494,9 +2062,19 @@ class SunriseSunsetTrigger < Trigger
|
|
1494
2062
|
|
1495
2063
|
end
|
1496
2064
|
|
2065
|
+
|
2066
|
+
class SensorsTrigger < Trigger
|
2067
|
+
|
2068
|
+
def initialize(h={})
|
2069
|
+
super(h)
|
2070
|
+
@group = 'sensors'
|
2071
|
+
end
|
2072
|
+
|
2073
|
+
end
|
2074
|
+
|
1497
2075
|
# Category: Sensors
|
1498
2076
|
#
|
1499
|
-
class ActivityRecognitionTrigger <
|
2077
|
+
class ActivityRecognitionTrigger < SensorsTrigger
|
1500
2078
|
|
1501
2079
|
def initialize(h={})
|
1502
2080
|
|
@@ -1506,31 +2084,70 @@ class ActivityRecognitionTrigger < Trigger
|
|
1506
2084
|
}
|
1507
2085
|
|
1508
2086
|
super(options.merge h)
|
2087
|
+
|
2088
|
+
@activity = ['In Vehicle', 'On Bicycle', 'Running', 'Walking', 'Still']
|
1509
2089
|
|
1510
2090
|
end
|
2091
|
+
|
2092
|
+
def to_s()
|
2093
|
+
activity = @activity[@h[:selected_index]]
|
2094
|
+
'Activity - ' + activity
|
2095
|
+
end
|
2096
|
+
|
2097
|
+
def to_summary
|
2098
|
+
|
2099
|
+
activity = @activity[@h[:selected_index]]
|
2100
|
+
s = if activity.length > 10 then
|
2101
|
+
activity[0..7] + '..'
|
2102
|
+
else
|
2103
|
+
activity
|
2104
|
+
end
|
2105
|
+
|
2106
|
+
'Activity - ' + s
|
2107
|
+
|
2108
|
+
end
|
1511
2109
|
|
1512
2110
|
end
|
1513
2111
|
|
1514
2112
|
# Category: Sensors
|
1515
2113
|
#
|
1516
|
-
class ProximityTrigger <
|
2114
|
+
class ProximityTrigger < SensorsTrigger
|
1517
2115
|
|
1518
2116
|
def initialize(h={})
|
1519
2117
|
|
2118
|
+
if h[:distance] then
|
2119
|
+
|
2120
|
+
case h[:distance].to_sym
|
2121
|
+
when :near
|
2122
|
+
options[:near] = true
|
2123
|
+
end
|
2124
|
+
end
|
2125
|
+
|
1520
2126
|
options = {
|
1521
2127
|
near: true,
|
1522
2128
|
selected_option: 0
|
1523
2129
|
}
|
1524
2130
|
|
1525
|
-
super(options.merge h)
|
2131
|
+
super(options.merge filter(options,h))
|
1526
2132
|
|
1527
2133
|
end
|
2134
|
+
|
2135
|
+
def to_s()
|
2136
|
+
|
2137
|
+
distance = if @h[:near] then
|
2138
|
+
'Near'
|
2139
|
+
else
|
2140
|
+
'Far'
|
2141
|
+
end
|
2142
|
+
|
2143
|
+
"Proximity Sensor (%s)" % distance
|
2144
|
+
end
|
1528
2145
|
|
1529
2146
|
end
|
1530
2147
|
|
1531
2148
|
# Category: Sensors
|
1532
2149
|
#
|
1533
|
-
class ShakeDeviceTrigger <
|
2150
|
+
class ShakeDeviceTrigger < SensorsTrigger
|
1534
2151
|
|
1535
2152
|
def initialize(h={})
|
1536
2153
|
|
@@ -1540,12 +2157,25 @@ class ShakeDeviceTrigger < Trigger
|
|
1540
2157
|
super(options.merge h)
|
1541
2158
|
|
1542
2159
|
end
|
2160
|
+
|
2161
|
+
def to_pc()
|
2162
|
+
'shake_device?'
|
2163
|
+
end
|
2164
|
+
|
2165
|
+
def to_s()
|
2166
|
+
'Shake Device'
|
2167
|
+
end
|
1543
2168
|
|
1544
2169
|
end
|
1545
2170
|
|
1546
2171
|
# Category: Sensors
|
1547
2172
|
#
|
1548
|
-
|
2173
|
+
# options:
|
2174
|
+
# Face Up -> Face Down
|
2175
|
+
# Face Down -> Face Up
|
2176
|
+
# Any -> Face Down
|
2177
|
+
#
|
2178
|
+
class FlipDeviceTrigger < SensorsTrigger
|
1549
2179
|
|
1550
2180
|
def initialize(h={})
|
1551
2181
|
|
@@ -1557,13 +2187,23 @@ class FlipDeviceTrigger < Trigger
|
|
1557
2187
|
|
1558
2188
|
super(options.merge h)
|
1559
2189
|
|
2190
|
+
end
|
2191
|
+
|
2192
|
+
def to_pc()
|
2193
|
+
@h[:face_down] ? 'flip_device_down?' : 'flip_device_up?'
|
1560
2194
|
end
|
2195
|
+
|
2196
|
+
def to_s()
|
2197
|
+
|
2198
|
+
action = @h[:face_down] ? 'Face Up -> Face Down' : 'Face Down -> Face Up'
|
2199
|
+
'Flip Device ' + action
|
2200
|
+
end
|
1561
2201
|
|
1562
2202
|
end
|
1563
2203
|
|
1564
2204
|
# Category: Sensors
|
1565
2205
|
#
|
1566
|
-
class OrientationTrigger <
|
2206
|
+
class OrientationTrigger < SensorsTrigger
|
1567
2207
|
|
1568
2208
|
def initialize(h={})
|
1569
2209
|
|
@@ -1745,6 +2385,10 @@ class LaunchActivityAction < ApplicationAction
|
|
1745
2385
|
super(options.merge h)
|
1746
2386
|
|
1747
2387
|
end
|
2388
|
+
|
2389
|
+
def to_s()
|
2390
|
+
'Launch ' + @h[:application_name]
|
2391
|
+
end
|
1748
2392
|
|
1749
2393
|
end
|
1750
2394
|
|
@@ -1770,6 +2414,8 @@ end
|
|
1770
2414
|
class OpenWebPageAction < ApplicationAction
|
1771
2415
|
|
1772
2416
|
def initialize(h={})
|
2417
|
+
|
2418
|
+
h[:url_to_open] = h[:url] if h[:url]
|
1773
2419
|
|
1774
2420
|
options = {
|
1775
2421
|
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},
|
@@ -1779,9 +2425,13 @@ class OpenWebPageAction < ApplicationAction
|
|
1779
2425
|
block_next_action: false
|
1780
2426
|
}
|
1781
2427
|
|
1782
|
-
super(options.merge h)
|
2428
|
+
super(options.merge filter(options,h))
|
1783
2429
|
|
1784
2430
|
end
|
2431
|
+
|
2432
|
+
def to_s()
|
2433
|
+
"HTTP GET\n url: " + @h[:url_to_open]
|
2434
|
+
end
|
1785
2435
|
|
1786
2436
|
end
|
1787
2437
|
|
@@ -1829,6 +2479,15 @@ class TakePictureAction < CameraAction
|
|
1829
2479
|
super(options.merge h)
|
1830
2480
|
|
1831
2481
|
end
|
2482
|
+
|
2483
|
+
def to_pc()
|
2484
|
+
camera = @h[:use_front_camera] ? :front : :back
|
2485
|
+
'take_photo :' + camera.to_s
|
2486
|
+
end
|
2487
|
+
|
2488
|
+
def to_s()
|
2489
|
+
'Take Picture'
|
2490
|
+
end
|
1832
2491
|
|
1833
2492
|
end
|
1834
2493
|
|
@@ -1857,6 +2516,11 @@ class SetWifiAction < ConnectivityAction
|
|
1857
2516
|
super(options.merge h)
|
1858
2517
|
|
1859
2518
|
end
|
2519
|
+
|
2520
|
+
def to_s()
|
2521
|
+
action = @h[:state] == 0 ? 'Enable' : 'Disable'
|
2522
|
+
action + ' Wifi'
|
2523
|
+
end
|
1860
2524
|
|
1861
2525
|
end
|
1862
2526
|
|
@@ -1987,6 +2651,20 @@ class SayTimeAction < DateTimeAction
|
|
1987
2651
|
super(options.merge h)
|
1988
2652
|
|
1989
2653
|
end
|
2654
|
+
|
2655
|
+
def invoke()
|
2656
|
+
time = ($env and $env[:time]) ? $env[:time] : Time.now
|
2657
|
+
tformat = @h['12_hour'] ? "%-I:%M%P" : "%H:%M"
|
2658
|
+
super(time.strftime(tformat))
|
2659
|
+
end
|
2660
|
+
|
2661
|
+
def to_pc()
|
2662
|
+
'say current_time()'
|
2663
|
+
end
|
2664
|
+
|
2665
|
+
def to_s()
|
2666
|
+
'Say Current Time'
|
2667
|
+
end
|
1990
2668
|
|
1991
2669
|
end
|
1992
2670
|
|
@@ -2067,6 +2745,10 @@ class SpeakTextAction < DeviceAction
|
|
2067
2745
|
super(options.merge h)
|
2068
2746
|
|
2069
2747
|
end
|
2748
|
+
|
2749
|
+
def to_s()
|
2750
|
+
"Speak Text (%s)" % @h[:text_to_say]
|
2751
|
+
end
|
2070
2752
|
|
2071
2753
|
end
|
2072
2754
|
|
@@ -2158,6 +2840,14 @@ class CameraFlashLightAction < DeviceSettingsAction
|
|
2158
2840
|
|
2159
2841
|
end
|
2160
2842
|
|
2843
|
+
def to_pc()
|
2844
|
+
'torch :on'
|
2845
|
+
end
|
2846
|
+
|
2847
|
+
def to_s()
|
2848
|
+
'Torch On'
|
2849
|
+
end
|
2850
|
+
|
2161
2851
|
end
|
2162
2852
|
|
2163
2853
|
# Category: Device Settings
|
@@ -2495,6 +3185,10 @@ class PlaySoundAction < MediaAction
|
|
2495
3185
|
super(options.merge h)
|
2496
3186
|
|
2497
3187
|
end
|
3188
|
+
|
3189
|
+
def to_s()
|
3190
|
+
'Play: ' + @h[:file_path]
|
3191
|
+
end
|
2498
3192
|
|
2499
3193
|
end
|
2500
3194
|
|
@@ -2699,6 +3393,9 @@ end
|
|
2699
3393
|
class NotificationAction < NotificationsAction
|
2700
3394
|
|
2701
3395
|
def initialize(h={})
|
3396
|
+
|
3397
|
+
h[:notification_subject] = h[:subject] if h[:subject]
|
3398
|
+
h[:notification_text] = h[:text] if h[:text]
|
2702
3399
|
|
2703
3400
|
options = {
|
2704
3401
|
ringtone_name: 'Default',
|
@@ -2714,9 +3411,13 @@ class NotificationAction < NotificationsAction
|
|
2714
3411
|
run_macro_when_pressed: false
|
2715
3412
|
}
|
2716
3413
|
|
2717
|
-
super(options.merge h)
|
3414
|
+
super(options.merge filter(options, h))
|
2718
3415
|
|
2719
3416
|
end
|
3417
|
+
|
3418
|
+
def to_s()
|
3419
|
+
'Display Notification: ' + "%s: %s" % [@h[:notification_subject], @h[:notification_text]]
|
3420
|
+
end
|
2720
3421
|
|
2721
3422
|
end
|
2722
3423
|
|
@@ -2750,6 +3451,10 @@ class ToastAction < NotificationsAction
|
|
2750
3451
|
super(@h[:message_text])
|
2751
3452
|
end
|
2752
3453
|
|
3454
|
+
def to_pc()
|
3455
|
+
"popup_message '%s'" % @h[:message_text]
|
3456
|
+
end
|
3457
|
+
|
2753
3458
|
def to_s()
|
2754
3459
|
"Popup Message '%s'" % @h[:message_text]
|
2755
3460
|
end
|
@@ -2945,6 +3650,10 @@ end
|
|
2945
3650
|
|
2946
3651
|
# Category: Screen
|
2947
3652
|
#
|
3653
|
+
# options:
|
3654
|
+
# keep awake, screen on => enabled: true
|
3655
|
+
# disable keep awake => enabled: false
|
3656
|
+
#
|
2948
3657
|
class KeepAwakeAction < ScreenAction
|
2949
3658
|
|
2950
3659
|
def initialize(h={})
|
@@ -2959,7 +3668,30 @@ class KeepAwakeAction < ScreenAction
|
|
2959
3668
|
super(options.merge h)
|
2960
3669
|
|
2961
3670
|
end
|
2962
|
-
|
3671
|
+
|
3672
|
+
def to_s()
|
3673
|
+
|
3674
|
+
screen = @h[:screen_option] == 0 ? 'Screen On' : 'Screen Off'
|
3675
|
+
|
3676
|
+
if @h[:enabled] then
|
3677
|
+
|
3678
|
+
whenx = if @h[:seconds_to_stay_awake_for] == 0 then
|
3679
|
+
|
3680
|
+
'Until Disabled'
|
3681
|
+
|
3682
|
+
else
|
3683
|
+
scnds = @h[:seconds_to_stay_awake_for]
|
3684
|
+
Subunit.new(units={minutes:60, hours:60}, seconds: scnds).strfunit("%x")
|
3685
|
+
end
|
3686
|
+
|
3687
|
+
'Keep Device Awake ' + screen + ' ' + whenx
|
3688
|
+
|
3689
|
+
else
|
3690
|
+
'Disable Keep Awake'
|
3691
|
+
end
|
3692
|
+
|
3693
|
+
|
3694
|
+
end
|
2963
3695
|
end
|
2964
3696
|
|
2965
3697
|
# Category: Screen
|
@@ -3489,6 +4221,18 @@ class AirplaneModeConstraint < Constraint
|
|
3489
4221
|
end
|
3490
4222
|
|
3491
4223
|
end
|
4224
|
+
|
4225
|
+
def to_pc()
|
4226
|
+
status = @h[:enabled] ? 'enabled?' : 'disabled?'
|
4227
|
+
'airplane_mode.' + status
|
4228
|
+
end
|
4229
|
+
|
4230
|
+
def to_s()
|
4231
|
+
|
4232
|
+
status = @h[:enabled] ? 'Enabled' : 'Disabled'
|
4233
|
+
'Airplane Mode ' + status
|
4234
|
+
|
4235
|
+
end
|
3492
4236
|
|
3493
4237
|
end
|
3494
4238
|
|