foscam-ruby 0.0.3 → 0.1.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 +6 -14
- data/.travis.yml +1 -1
- data/foscam-ruby.gemspec +1 -0
- data/lib/foscam-ruby.rb +20 -0
- data/lib/foscam/client.rb +69 -248
- data/lib/foscam/constants.rb +144 -0
- data/lib/foscam/model/alarm_config.rb +147 -0
- data/lib/foscam/model/base.rb +48 -0
- data/lib/foscam/model/device.rb +92 -0
- data/lib/foscam/model/ftp_server.rb +109 -0
- data/lib/foscam/model/mail_server.rb +124 -0
- data/lib/foscam/model/network.rb +79 -0
- data/lib/foscam/model/user.rb +174 -0
- data/lib/foscam/schedule/day.rb +63 -0
- data/lib/foscam/schedule/third_of_a_day.rb +42 -0
- data/lib/foscam/schedule/week.rb +89 -0
- data/lib/foscam/version.rb +1 -1
- data/spec/foscam/client_spec.rb +18 -60
- data/spec/foscam/model/alarm_config_spec.rb +164 -0
- data/spec/foscam/model/base_spec.rb +22 -0
- data/spec/foscam/model/device_spec.rb +136 -0
- data/spec/foscam/model/ftp_server_spec.rb +135 -0
- data/spec/foscam/model/mail_server_spec.rb +126 -0
- data/spec/foscam/model/network_spec.rb +128 -0
- data/spec/foscam/model/user_spec.rb +322 -0
- data/spec/foscam/schedule/day_spec.rb +37 -0
- data/spec/foscam/schedule/third_of_a_day_spec.rb +42 -0
- data/spec/foscam/schedule/week_spec.rb +109 -0
- metadata +64 -19
@@ -0,0 +1,124 @@
|
|
1
|
+
module Foscam
|
2
|
+
module Model
|
3
|
+
class MailServer < Base
|
4
|
+
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
class Recipient
|
8
|
+
|
9
|
+
include Singleton
|
10
|
+
include ::ActiveModel::Dirty
|
11
|
+
include ::ActiveModel::Validations
|
12
|
+
include ::ActiveModel::Conversion
|
13
|
+
extend ::ActiveModel::Naming
|
14
|
+
extend ::ActiveModel::Translation
|
15
|
+
|
16
|
+
|
17
|
+
attr_accessor :id
|
18
|
+
|
19
|
+
attr_reader :address
|
20
|
+
|
21
|
+
define_attribute_methods [:address]
|
22
|
+
|
23
|
+
def initialize(params = nil)
|
24
|
+
params.each do |attr, value|
|
25
|
+
self.public_send("#{attr}=", value)
|
26
|
+
end if params
|
27
|
+
end
|
28
|
+
|
29
|
+
def address=(val)
|
30
|
+
address_will_change! unless val == @address
|
31
|
+
@address = val
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
define_model_callbacks :save, :clear
|
37
|
+
|
38
|
+
attr_reader :username, :password, :address, :port, :sender, :recipients
|
39
|
+
|
40
|
+
|
41
|
+
def sender=(val)
|
42
|
+
sender_will_change! unless val == @sender
|
43
|
+
@sender = val
|
44
|
+
end
|
45
|
+
|
46
|
+
def username=(val)
|
47
|
+
username_will_change! unless val == @username
|
48
|
+
@username = val
|
49
|
+
end
|
50
|
+
|
51
|
+
def password=(val)
|
52
|
+
password_will_change! unless val == @password
|
53
|
+
@password = val
|
54
|
+
end
|
55
|
+
|
56
|
+
def address=(val)
|
57
|
+
address_will_change! unless val == @address
|
58
|
+
@address = val
|
59
|
+
end
|
60
|
+
|
61
|
+
def port=(val)
|
62
|
+
port_will_change! unless val == @port
|
63
|
+
@port = val
|
64
|
+
end
|
65
|
+
|
66
|
+
def client=(obj)
|
67
|
+
unless obj.nil?
|
68
|
+
MailServer::client = obj
|
69
|
+
params = client.get_params
|
70
|
+
unless params.empty?
|
71
|
+
self.sender = params[:mail_sender]
|
72
|
+
self.address = params[:mail_svr]
|
73
|
+
self.port = params[:mail_port]
|
74
|
+
self.username = params[:mail_user]
|
75
|
+
self.password = params[:mail_pwd]
|
76
|
+
@recipients = []
|
77
|
+
(1..4).each do |i|
|
78
|
+
@recipients << Recipient.new(:id => i, :address => params["mail_receiver#{i}".to_sym]) if params.has_key?("mail_receiver#{i}".to_sym) && !params["mail_receiver#{i}".to_sym].empty?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
define_attribute_methods [:username, :password, :address, :port, :sender]
|
85
|
+
|
86
|
+
def save
|
87
|
+
run_callbacks :save do
|
88
|
+
flag = false
|
89
|
+
if changed? && is_valid?
|
90
|
+
@previously_changed = changes
|
91
|
+
flag = client.set_mail(dirty_params_hash)
|
92
|
+
@changed_attributes.clear if flag
|
93
|
+
end
|
94
|
+
flag
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def clear
|
99
|
+
run_callbacks :clear do
|
100
|
+
flag = false
|
101
|
+
params = {:sender => "", :user => "", :pwd => "", :svr => "", :port => 21, :receiver1 => "", :receiver2 => "", :receiver3 => "", :receiver4 => ""}
|
102
|
+
flag = client.set_mail(params)
|
103
|
+
@changed_attributes.clear if flag
|
104
|
+
flag
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def dirty_params_hash
|
111
|
+
h = {}
|
112
|
+
h.merge!({:sender => self.sender}) if sender_changed?
|
113
|
+
h.merge!({:user => self.username}) if username_changed?
|
114
|
+
h.merge!({:pwd => self.password}) if password_changed?
|
115
|
+
h.merge!({:svr => self.address}) if address_changed?
|
116
|
+
h.merge!({:port => self.port}) if port_changed?
|
117
|
+
self.recipients.each do |recipient|
|
118
|
+
h.merge!({"receiver#{recipient.id}".to_sym => recipient.address}) if recipient.address_changed?
|
119
|
+
end
|
120
|
+
h
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Foscam
|
2
|
+
module Model
|
3
|
+
class Network < Base
|
4
|
+
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
attr_reader :ip_address, :mask, :gateway, :dns, :port
|
8
|
+
|
9
|
+
define_model_callbacks :save
|
10
|
+
|
11
|
+
|
12
|
+
def ip_address=(val)
|
13
|
+
ip_address_will_change! unless val == @ip_address
|
14
|
+
@ip_address = val
|
15
|
+
end
|
16
|
+
|
17
|
+
def mask=(val)
|
18
|
+
mask_will_change! unless val == @mask
|
19
|
+
@mask = val
|
20
|
+
end
|
21
|
+
|
22
|
+
def gateway=(val)
|
23
|
+
gateway_will_change! unless val == @gateway
|
24
|
+
@gateway = val
|
25
|
+
end
|
26
|
+
|
27
|
+
def dns=(val)
|
28
|
+
dns_will_change! unless val == @dns
|
29
|
+
@dns = val
|
30
|
+
end
|
31
|
+
|
32
|
+
def port=(val)
|
33
|
+
port_will_change! unless val == @port
|
34
|
+
@port = val
|
35
|
+
end
|
36
|
+
|
37
|
+
def client=(obj)
|
38
|
+
unless obj.nil?
|
39
|
+
Network::client = obj
|
40
|
+
params = client.get_params
|
41
|
+
unless params.empty?
|
42
|
+
self.ip_address = params[:ip]
|
43
|
+
self.mask = params[:mask]
|
44
|
+
self.gateway = params[:gateway]
|
45
|
+
self.dns = params[:dns]
|
46
|
+
self.port = params[:port]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
define_attribute_methods [:ip_address, :mask, :gateway, :dns, :port]
|
52
|
+
|
53
|
+
def save
|
54
|
+
run_callbacks :save do
|
55
|
+
flag = false
|
56
|
+
if changed? && is_valid?
|
57
|
+
@previously_changed = changes
|
58
|
+
flag = client.set_network(dirty_params_hash)
|
59
|
+
@changed_attributes.clear if flag
|
60
|
+
end
|
61
|
+
flag
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def dirty_params_hash
|
68
|
+
h = {}
|
69
|
+
h.merge!({:ip => self.ip_address }) if ip_address_changed?
|
70
|
+
h.merge!({:mask => self.mask }) if mask_changed?
|
71
|
+
h.merge!({:gateway => self.gateway }) if gateway_changed?
|
72
|
+
h.merge!({:dns => self.dns }) if dns_changed?
|
73
|
+
h.merge!({:port => self.port }) if port_changed?
|
74
|
+
h
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Foscam
|
2
|
+
module Model
|
3
|
+
class User < Base
|
4
|
+
|
5
|
+
# Max number of users supported by foscam
|
6
|
+
MAX_NUMBER = 8
|
7
|
+
|
8
|
+
# :nodoc
|
9
|
+
define_model_callbacks :save, :create, :destroy
|
10
|
+
|
11
|
+
##
|
12
|
+
# @!attribute [r] id
|
13
|
+
# @return [Fixnum] The id of the user
|
14
|
+
attr_reader :id
|
15
|
+
|
16
|
+
##
|
17
|
+
# @!attribute [rw] username
|
18
|
+
# @return [String] The name of the user
|
19
|
+
attr_reader :username
|
20
|
+
|
21
|
+
##
|
22
|
+
# @!attribute [rw] password
|
23
|
+
# @return [String] The password of the user
|
24
|
+
attr_reader :password
|
25
|
+
|
26
|
+
##
|
27
|
+
# @!attribute [rw] privilege
|
28
|
+
# @return [Symbol] The privilege of the user
|
29
|
+
attr_reader :privilege
|
30
|
+
|
31
|
+
define_attribute_methods [:username, :password, :privilege]
|
32
|
+
|
33
|
+
|
34
|
+
def username=(val)
|
35
|
+
username_will_change! unless val == @username
|
36
|
+
@username = val
|
37
|
+
end
|
38
|
+
|
39
|
+
def password=(val)
|
40
|
+
password_will_change! unless val == @password
|
41
|
+
@password = val
|
42
|
+
end
|
43
|
+
|
44
|
+
def privilege=(val)
|
45
|
+
privilege_will_change! unless val == @privilege
|
46
|
+
@privilege = val
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Get all the users
|
51
|
+
# @return [Array] of Users
|
52
|
+
def self.all
|
53
|
+
cam_params = client.get_params
|
54
|
+
users = []
|
55
|
+
unless cam_params.empty?
|
56
|
+
(1..8).each do |i|
|
57
|
+
unless cam_params["user#{i}_name".to_sym].empty?
|
58
|
+
user = User.new(:username => cam_params["user#{i}_name".to_sym], :password => cam_params["user#{i}_pwd".to_sym], :privilege => cam_params["user#{i}_pri".to_sym])
|
59
|
+
user.instance_variable_set(:@id, i)
|
60
|
+
users << user
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
users
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Create a user with the specified parameters
|
69
|
+
# @param params [Hash] User attributes
|
70
|
+
# @option params [String] :username
|
71
|
+
# @option params [String] :password
|
72
|
+
# @option params [Symbol] :privilege
|
73
|
+
# @return [User, nil] Returns the user if successfully saved
|
74
|
+
def self.create(params ={})
|
75
|
+
user = User.new(params)
|
76
|
+
user.save ? user : nil
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
##
|
81
|
+
# Find a specific user by name
|
82
|
+
# @param id [Fixnum] The id of the user
|
83
|
+
# @return [User]
|
84
|
+
def self.find(id)
|
85
|
+
user = nil
|
86
|
+
if id > 0 && id <= MAX_NUMBER
|
87
|
+
cam_params = client.get_params
|
88
|
+
if !cam_params.empty? && !cam_params["user#{id}_name".to_sym].empty?
|
89
|
+
user = User.new(:username => cam_params["user#{id}_name".to_sym], :password => cam_params["user#{id}_pwd".to_sym], :privilege => cam_params["user#{id}_pri".to_sym])
|
90
|
+
user.instance_variable_set(:@id, id)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
user
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Delete a user by the id
|
98
|
+
# @param id [Fixnum] The id of the user
|
99
|
+
# @return [FalseClass, TrueClass] Whether or not the user was successfully deleted
|
100
|
+
def self.delete(id)
|
101
|
+
params = {"user#{id}".to_sym => "", "pwd#{id}".to_sym => "", "pri#{id}".to_sym => 0}
|
102
|
+
id > 0 && id <= MAX_NUMBER ? client.set_users(params) : false
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
##
|
107
|
+
# Save the current user to the camera
|
108
|
+
# @return [FalseClass, TrueClass] Whether or not the user was successfully saved
|
109
|
+
def save
|
110
|
+
run_callbacks :save do
|
111
|
+
flag = false
|
112
|
+
if changed? && is_valid? && set_id
|
113
|
+
@previously_changed = changes
|
114
|
+
# Get the first user that is not taken
|
115
|
+
flag = client.set_users(dirty_params_hash)
|
116
|
+
@changed_attributes.clear if flag
|
117
|
+
end
|
118
|
+
flag
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Check for User equality
|
124
|
+
# @param other [User]
|
125
|
+
# @return [FalseClass, TrueClass] Whether or not the users are the same
|
126
|
+
def ==(other)
|
127
|
+
other.equal?(self) || ( other.instance_of?(self.class) && other.id == @id && !other.id.nil? && !@id.nil?)
|
128
|
+
end
|
129
|
+
|
130
|
+
##
|
131
|
+
# Delete the current user
|
132
|
+
# @return [FalseClass, TrueClass] Whether or not the user was successfully deleted
|
133
|
+
def destroy
|
134
|
+
run_callbacks :destroy do
|
135
|
+
self.username = ""
|
136
|
+
self.password = ""
|
137
|
+
self.privilege = 0
|
138
|
+
flag = @id.nil? ? false : client.set_users(dirty_params_hash)
|
139
|
+
@changed_attributes.clear
|
140
|
+
flag
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def dirty_params_hash
|
147
|
+
h = {}
|
148
|
+
h.merge!({"user#{@id}".to_sym => @username}) if username_changed?
|
149
|
+
h.merge!({"pwd#{@id}".to_sym => @password}) if password_changed?
|
150
|
+
h.merge!({"pri#{@id}".to_sym => @privilege}) if privilege_changed?
|
151
|
+
h
|
152
|
+
end
|
153
|
+
|
154
|
+
def set_id
|
155
|
+
flag = false
|
156
|
+
if @id.nil?
|
157
|
+
cam_params = client.get_params
|
158
|
+
unless cam_params.empty?
|
159
|
+
(1..8).each do |i|
|
160
|
+
if cam_params["user#{i}_name".to_sym].empty?
|
161
|
+
@id = i
|
162
|
+
flag = true
|
163
|
+
break
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
else
|
168
|
+
flag = true
|
169
|
+
end
|
170
|
+
flag
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Foscam
|
2
|
+
module Schedule
|
3
|
+
class Day
|
4
|
+
|
5
|
+
##
|
6
|
+
# @param bit1 [Fixnum] The 32-bit bitmask representing the first third of the day
|
7
|
+
# @param bit2 [Fixnum] The 32-bit bitmask representing the second third of the day
|
8
|
+
# @param bit3 [Fixnum] The 32-bit bitmask representing the last third of the day
|
9
|
+
def initialize(bit1, bit2, bit3)
|
10
|
+
self.bits = Array.new(3)
|
11
|
+
self.bits[0] = ThirdOfADay.new(bit1)
|
12
|
+
self.bits[1] = ThirdOfADay.new(bit2)
|
13
|
+
self.bits[2] = ThirdOfADay.new(bit3)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :bits
|
17
|
+
|
18
|
+
##
|
19
|
+
# Determine if the the schedule is true at the given date time
|
20
|
+
# @param time [Time, Fixnum, DateTime] Accepts multiple forms of time. If a Datetime or Time is used then only the time of day is used. If a fixnum is given then it is a number representing the number of seconds from the start of the day.
|
21
|
+
# @return [FalseClass, TrueClass] Whether it is busy at that time
|
22
|
+
def busy_at?(time)
|
23
|
+
case time
|
24
|
+
when Fixnum
|
25
|
+
bit = seconds/28800
|
26
|
+
bit_num = bit_from_time(seconds/3600, seconds % 3600)
|
27
|
+
when DateTime
|
28
|
+
time = time.to_time
|
29
|
+
bit = time.hour / 8
|
30
|
+
bit_num = bit_from_time(time.hour, time.min)
|
31
|
+
when Time
|
32
|
+
bit = time.hour / 8
|
33
|
+
bit_num = bit_from_time(time.hour, time.min)
|
34
|
+
else
|
35
|
+
|
36
|
+
end
|
37
|
+
self.bits[bit].active?(bit_num)
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Convert the Week to a nested hash with the day of the week as the key and and time as the second key
|
42
|
+
# @return [Hash]
|
43
|
+
def to_hash
|
44
|
+
h = {}
|
45
|
+
self.bits.each_index do |idx|
|
46
|
+
bits[idx].to_hash.each do |j, value|
|
47
|
+
minute = (j % 4) * 15
|
48
|
+
hour = j / 4 + idx * 8
|
49
|
+
h.merge!("#{"%02d" % hour}:#{"%02d" % minute}" => value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
h
|
53
|
+
end
|
54
|
+
|
55
|
+
# takes three integers
|
56
|
+
private
|
57
|
+
|
58
|
+
def bit_from_time(hours, minutes)
|
59
|
+
(hours % 8)*4 + minutes/15
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
module Foscam
|
3
|
+
module Schedule
|
4
|
+
class ThirdOfADay
|
5
|
+
|
6
|
+
attr_accessor :bit
|
7
|
+
|
8
|
+
##
|
9
|
+
# @param bit [Fixnum] The 32-bit bitmask representing 8 hours divided into 15 minute blocks
|
10
|
+
def initialize(bit)
|
11
|
+
self.bit = bit
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Returns whether the bit is positive or not
|
16
|
+
# @param idx [Fixnum] The bit index representing the 15 minute block
|
17
|
+
# @return [FalseClass, TrueClass] Whether the bit is equal to 1
|
18
|
+
def active?(idx)
|
19
|
+
binary_string[31-idx].to_i > 0
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Convert the bitmask representing a third of a day with a Hash. The key is the idx of the bit and the value is a boolean of whether it is active or not
|
24
|
+
# @return [Hash]
|
25
|
+
def to_hash
|
26
|
+
h = {}
|
27
|
+
i = 0
|
28
|
+
binary_string.reverse.each_char do |char|
|
29
|
+
h.merge!({i => char.to_i > 0})
|
30
|
+
i = i + 1
|
31
|
+
end
|
32
|
+
h
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def binary_string
|
38
|
+
@str ||= ("%032d" % self.bit.to_s(2))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|