remotedroid 0.4.0 → 0.5.0
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/remotedroid.rb +84 -536
- data/lib/remotedroid/client.rb +157 -0
- data/lib/remotedroid/control.rb +194 -0
- data/lib/remotedroid/controller.rb +150 -0
- data/lib/remotedroid/model.rb +227 -0
- data/lib/remotedroid/query.rb +60 -0
- metadata +9 -4
- metadata.gz.sig +0 -0
@@ -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
|