remotedroid 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,157 @@
1
+ module RemoteDroid
2
+
3
+ class Client
4
+ using ColouredText
5
+
6
+ def initialize(host='127.0.0.1')
7
+ @drb = OneDrb::Client.new host: host, port: '5777'
8
+ end
9
+
10
+ def control
11
+ @drb.control
12
+ end
13
+
14
+ def export(s)
15
+ @drb.export(s)
16
+ end
17
+
18
+ def invoke(s, *args)
19
+ @drb.invoke(s, *args)
20
+ end
21
+
22
+ def macros()
23
+ @drb.macros
24
+ end
25
+
26
+ def query(id=nil)
27
+
28
+ return @drb.query unless id
29
+ t = Time.now
30
+ h = @drb.query(id)
31
+ h.merge({latency: (Time.now - t).round(3)})
32
+
33
+ end
34
+
35
+ def update(key, val)
36
+ @drb.update key.to_sym, val
37
+ end
38
+
39
+ def store()
40
+ @drb.store
41
+ end
42
+
43
+ # -- helpful methods -----------------
44
+
45
+ def battery()
46
+ query.battery
47
+ end
48
+
49
+ def cell_tower()
50
+ query.cell_tower
51
+ end
52
+
53
+ def disable(macro)
54
+ control.disable macro
55
+ end
56
+
57
+ def enable(macro)
58
+ control.enable macro
59
+ end
60
+
61
+ def hotspot(state=nil)
62
+ control.hotspot state
63
+ end
64
+
65
+ def location()
66
+ query.location
67
+ end
68
+
69
+ def location_watch(refresh: '1 minute', interval: refresh,
70
+ duration: '30 minutes')
71
+
72
+
73
+ d = ChronicDuration.parse(duration)
74
+ seconds = ChronicDuration.parse(interval)
75
+ puts ("monitoring location every %s for %s" % [interval, duration]).info
76
+
77
+ Thread.new do
78
+
79
+ t = Time.now + d
80
+
81
+ begin
82
+
83
+ query.location
84
+ sleep seconds
85
+
86
+ end until Time.now >= t
87
+
88
+ end
89
+
90
+ end
91
+
92
+ def photo()
93
+ take_picture
94
+ end
95
+
96
+ def say(text)
97
+ control.speak_text text
98
+ end
99
+
100
+ def say_time()
101
+ control.say_time
102
+ end
103
+
104
+ alias saytime say_time
105
+
106
+ def screen(state=nil)
107
+ control.screen state
108
+ end
109
+
110
+ def screen_on()
111
+ screen :on
112
+ end
113
+
114
+ def screen_off()
115
+ screen :off
116
+ end
117
+
118
+ def stay_awake()
119
+ control.stay_awake
120
+ end
121
+
122
+ def stay_awake_off()
123
+ control.stay_awake_off
124
+ end
125
+
126
+ def take_picture(ftp_src: nil, fileout: '.')
127
+
128
+ #screen.on
129
+ r = query.take_picture
130
+
131
+ if ftp_src then
132
+
133
+ # give the device a second to write the image to file
134
+ sleep 1
135
+
136
+ credentials, dir = ftp_src.match(/(ftp:\/\/[^\/]+)\/([^$]+)/).captures
137
+ ftp = MyMediaFTP.new(credentials)
138
+ ftp.cd dir
139
+ filename = ftp.ls.sort_by {|x| x[:ctime]}.last[:name]
140
+ ftp.cp filename, fileout
141
+
142
+ end
143
+
144
+ end
145
+
146
+ alias take_photo take_picture
147
+
148
+ def torch()
149
+ control.torch
150
+ end
151
+
152
+ def vibrate
153
+ control.vibrate
154
+ end
155
+
156
+ end
157
+ end
@@ -0,0 +1,194 @@
1
+ module RemoteDroid
2
+
3
+ class Control
4
+
5
+ def initialize(dev=nil, deviceid: dev, remote_url: nil, debug: false)
6
+
7
+ @deviceid, @remote_url, @debug = deviceid, remote_url, debug
8
+
9
+ end
10
+
11
+ def bluetooth()
12
+ @bluetooth
13
+ end
14
+
15
+ def camera_flash_light(options={})
16
+ http_exec 'camera-flash-light', options
17
+ end
18
+
19
+ def disable(macro)
20
+ http_exec 'disable-macro', {name: macro}
21
+ end
22
+
23
+ def enable(macro)
24
+ http_exec 'enable-macro', {name: macro}
25
+ end
26
+
27
+ def hotspot(state=nil)
28
+
29
+ if state then
30
+ http_exec 'hotspot', {enable: state == :enable}
31
+ else
32
+
33
+ def self.enable()
34
+ http_exec 'hotspot', {enable: true}
35
+ end
36
+
37
+ def self.on()
38
+ self.enable
39
+ end
40
+
41
+ def self.disable()
42
+ http_exec 'hotspot', {enable: false}
43
+ end
44
+
45
+ def self.off()
46
+ self.disable
47
+ end
48
+
49
+ self
50
+
51
+ end
52
+ end
53
+
54
+ def http_exec(command, options={})
55
+
56
+ url = "https://trigger.macrodroid.com/%s/%s" % [@deviceid, command]
57
+
58
+ if options and options.any? then
59
+ h = options
60
+ url += '?' + \
61
+ URI.escape(h.map {|key,value| "%s=%s" % [key, value]}.join('&'))
62
+ end
63
+
64
+ s = open(url).read
65
+
66
+ end
67
+
68
+ def location(options={})
69
+ http_exec 'location'
70
+ end
71
+
72
+ def say_current_time(options={})
73
+ http_exec 'say-current-time'
74
+ end
75
+
76
+ alias say_time say_current_time
77
+
78
+ def screen(state=nil)
79
+
80
+ if state then
81
+ http_exec 'screen', {on: state == :on}
82
+ else
83
+
84
+ def self.on()
85
+ http_exec 'screen', {on: true}
86
+ end
87
+
88
+ def self.off()
89
+ http_exec 'screen', {on: false}
90
+ end
91
+
92
+ self
93
+
94
+ end
95
+ end
96
+
97
+ def share_location(options={})
98
+ http_exec 'share-location'
99
+ end
100
+
101
+ def speak_text(obj)
102
+
103
+ options = case obj
104
+ when String
105
+ {text: obj}
106
+ when Hash
107
+ obj
108
+ end
109
+
110
+ http_exec 'speak-text', options
111
+ end
112
+
113
+ alias say speak_text
114
+
115
+ def stay_awake(options={})
116
+ http_exec 'stay-awake', options
117
+ end
118
+
119
+ def stay_awake_off(options={})
120
+ http_exec 'stay-awake-off', options
121
+ end
122
+
123
+ def take_picture(options={})
124
+ http_exec 'take-picture', options
125
+ end
126
+
127
+ alias take_photo take_picture
128
+
129
+
130
+ def toast(options={})
131
+ http_exec :toast, options
132
+ end
133
+
134
+ def torch(options={})
135
+ http_exec :torch
136
+ end
137
+
138
+ def vibrate(options={})
139
+ http_exec :vibrate
140
+ end
141
+
142
+
143
+ def write(s)
144
+
145
+ d = MacroDroid.new(RD_MACROS, deviceid: @deviceid,
146
+ remote_url: @remote_url, debug: false)
147
+
148
+ a = d.macros.select do |macro|
149
+
150
+ macro.triggers.find {|trigger| trigger.is_a? WebHookTrigger }.nil?
151
+
152
+ end
153
+ puts 'a: ' + a.length.inspect
154
+
155
+ aux_macros = %w(Disable Enable).map do |state|
156
+
157
+ rows = a[1..-1].map do |macro|
158
+
159
+ " Else If name = #{macro.title}
160
+ #{state} macro
161
+ #{macro.title}"
162
+ end
163
+
164
+ "
165
+ m: #{state} macro
166
+ v: name
167
+ t: webhook
168
+ a:
169
+ If name = #{a[0].title}
170
+ #{state} macro
171
+ #{a[0].title}
172
+ #{rows.join("\n")}
173
+ End If
174
+ " end
175
+
176
+ puts aux_macros.join
177
+ d.import aux_macros.join
178
+
179
+ # disable the non-webhook triggers by default
180
+ a.each(&:disable)
181
+
182
+ d.export s
183
+ puts 'exported to ' + s
184
+
185
+ end
186
+
187
+ alias export write
188
+
189
+ def method_missing2(method_name, *args)
190
+ http_exec(method_name, args.first)
191
+ end
192
+
193
+ end
194
+ end
@@ -0,0 +1,150 @@
1
+ module RemoteDroid
2
+
3
+ class Controller
4
+
5
+ attr_reader :model, :control
6
+ attr_accessor :title, :macros, :store
7
+
8
+ def initialize(mcs, model=MODEL, deviceid: nil, debug: false)
9
+
10
+ @debug = debug
11
+ @syslog = []
12
+
13
+ @control = Control.new(deviceid)
14
+ @macros = mcs.macros
15
+
16
+ if model then
17
+ @model = Model.new(model)
18
+ end
19
+
20
+ @store = {}
21
+ @query = Query.new(self)
22
+
23
+ # enable the required triggers on the Android device
24
+ #
25
+ names = @macros.map {|x| x.triggers.first.type}.uniq
26
+ #@control.enable names.first.to_s.gsub('_',' ')
27
+ puts 'Enabling ' + names.join(',')
28
+
29
+ Thread.new do
30
+ names.each do |title|
31
+ @control.enable title.to_s.gsub('_',' ')
32
+ sleep 0.8
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ def export(s)
39
+ @macros = MacroDroid.new(s).macros
40
+ end
41
+
42
+ def invoke(name, options={})
43
+
44
+ if @control.respond_to? name.to_sym then
45
+ @control.method(name.to_sym).call(options)
46
+ else
47
+ @control.http_exec name.to_sym, options
48
+ end
49
+ end
50
+
51
+ # Object Property (op)
52
+ # Helpful for accessing properites in dot notation
53
+ # e.g. op.livingroom.light.switch = 'off'
54
+ #
55
+ def op()
56
+ @model.op
57
+ end
58
+
59
+ def query(id=nil)
60
+
61
+ return @query unless id
62
+
63
+ @store[id] = nil
64
+
65
+ sys = %i(accelerometer_rotation)
66
+
67
+ global = [:airplane_mode_on, :bluetooth_on, :cell_on, :device_name, \
68
+ :usb_mass_storage_enabled, :wifi_on]
69
+
70
+ secure = %i(bluetooth_name flashlight_enabled)
71
+
72
+
73
+ # send http request via macrodroid.com API
74
+
75
+ if id.downcase.to_sym == :location then
76
+ @control.http_exec id
77
+ elsif sys.include? id
78
+ @control.http_exec :'query-setting-system', {qvar: id}
79
+ elsif global.include? id
80
+ @control.http_exec :'query-setting-global', {qvar: id}
81
+ elsif secure.include? id
82
+ @control.http_exec :'query-setting-secure', {qvar: id}
83
+ elsif id.downcase.to_sym == :'take-picture'
84
+ @control.http_exec id
85
+ else
86
+ @control.http_exec :query, {qvar: id}
87
+ end
88
+
89
+ # wait for the local variable to be updated
90
+ # timeout after 5 seoncds
91
+ t = Time.now
92
+
93
+ begin
94
+ sleep 1
95
+ end until @store[id] or Time.now > t + 10
96
+
97
+ return {warning: 'HTTP response timeout'} if Time.now > t+5
98
+
99
+ return @store[id]
100
+
101
+
102
+ end
103
+
104
+ def request(s)
105
+ @model.request s
106
+ end
107
+
108
+
109
+ def trigger(name, detail={time: Time.now})
110
+
111
+ macros = @macros.select do |macro|
112
+
113
+ puts 'macro: ' + macro.inspect if @debug
114
+
115
+ # fetch the associated properties from the model if possible and
116
+ # merge them into the detail.
117
+ #
118
+ valid_trigger = macro.match?(name, detail, @model.op)
119
+
120
+ puts 'valid_trigger: ' + valid_trigger.inspect if @debug
121
+
122
+ if valid_trigger then
123
+ @syslog << [Time.now, :trigger, name]
124
+ @syslog << [Time.now, :macro, macro.title]
125
+ end
126
+
127
+ valid_trigger
128
+
129
+ end
130
+
131
+ puts 'macros: ' + macros.inspect if @debug
132
+
133
+ macros.flat_map(&:run)
134
+ end
135
+
136
+ alias trigger_fired trigger
137
+
138
+ def update(id, val)
139
+
140
+ key = if %i(location take-picture).include? id
141
+ id
142
+ else
143
+ val.keys.first.to_sym
144
+ end
145
+
146
+ @store[key] = val
147
+ end
148
+
149
+ end
150
+ end