-
Notifications
You must be signed in to change notification settings - Fork 2
/
fi8918w.py
199 lines (171 loc) · 7.61 KB
/
fi8918w.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import urllib2
import re
import base64
import sys
class Fi8918w:
"""
This class can be used to send commands to a Foscam FI8918W IP camera.
"""
def __init__(self, realm="", url="", username="", password=""):
self.realm = realm
self.camera_url = url
self.username = username
self.password = password
self.camera_id = ""
self.camera_name = ""
self.alarm_status = ""
self.authheader = None
# ---------- Private methods ----------
def _digest_auth(self, url):
authhandler = urllib2.HTTPDigestAuthHandler()
authhandler.add_password(self.realm, self.camera_url, self.username, self.password)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
page_content = urllib2.urlopen(url)
def _query_camera(self, command):
""" This method sends requests/commands to the camera when the return does not need to be saved to a binary file.
:param command: cgi request/command to the camera
:return: returns the urllib2.urlopen return value
"""
if not self.camera_url or not command:
return -1
nurl = "http://" + self.camera_url + "/" + command
# Set up the basic authentication, and get the data
return self._digest_auth(nurl)
def _query_camera_binary(self, command):
"""
This method sends requests/commands to the camera when the return does need to be saved to a binary file.
Used for saving snapshots from the camera for example.
:param command: cgi request/command to the camera
:param arg: base pathname and file name without extension where the picture will be saved
:return: pathname and filename of the output file
"""
if not self.camera_url or not command:
return -1
nurl = "http://" + self.camera_url + "/" + command
b = urllib2.urlopen(nurl)
return b.read()
def _cam_ptz_step(self, command, degrees):
if degrees < 1:
# invalid movement amount makes the camera do funny things
return -1
return self._query_camera('decoder_control.cgi?command={0}&onestep=1°ree={1}'.format(command, degrees))
# ---------- Public methods ----------
def get_status(self):
resp = self._query_camera('get_params.cgi')
if resp == -1:
status = -1
else:
status = {}
for line in resp:
line = line[4:] # strip "var "
line = line.rstrip(';\n')
parts = line.split('=')
if len(parts) > 1:
status[parts[0]] = parts[1].replace("'", "")
self.camera_id = status['id']
self.camera_name = status['alias']
return status
def set_motion_alarm(self, alarm):
if alarm:
arg = "motion_armed=1"
else:
arg = "motion_armed=0"
resp = self._query_camera('set_alarm.cgi', arg)
return -1 if resp == -1 else 1
def get_snapshot(self, fname=None):
""" This method gets a snapshot from the camera and returns the image string. If a filename is specified it writes
out to the file too
:param fname: optional, name of an image file to which the data will be written
:return: returns the image string
"""
img_str = self._query_camera_binary('snapshot.cgi')
if fname:
with open(fname, 'wb') as fout:
fout.write(img_str)
return img_str
def ir_on(self):
""" This method sends command 95 to the camera which turns on the infrared emitters
:return: returns the url2lib response from the camera
"""
resp = self._query_camera('decoder_control.cgi?command=95')
return resp
def ir_off(self):
""" This method sends command 94 to the camera which turns off the infrared emitters
:return: returns the url2lib response from the camera
"""
return self._query_camera('decoder_control.cgi?command=94')
def cam_center(self):
""" This method sends command 25 to the camera which runs a set of movements that centers the camera
:return: returns the url2lib response from the camera
"""
resp = self._query_camera('decoder_control.cgi?command=25')
return resp
def cam_step_up(self, degrees=1):
""" Send command 0 (up) to the decoder_control.cgi to make the camera move up
:param degrees: degrees of the desired move
:return: -1 on invalid commands or move amount
"""
return self._cam_ptz_step(command=0, degrees=degrees)
def cam_step_down(self, degrees=1):
""" Send command 2 (down) to the decoder_control.cgi to make the camera move down
:param degrees: degrees of the desired move
:return: -1 on invalid commands or move amount
"""
return self._cam_ptz_step(command=2, degrees=degrees)
def cam_step_left(self, degrees=1):
""" Send command 6 (left) to the decoder_control.cgi to make the camera move left. Note this is opposite of the
camera documentation. This was tested with camera on desk.
:param degrees: degrees of the desired move
:return: -1 on invalid commands or move amount
"""
return self._cam_ptz_step(command=4, degrees=degrees)
def cam_step_right(self, degrees=1):
""" Send command 4 (right) to the decoder_control.cgi to make the camera move right. Note this is opposite of the
camera documentation. This was tested with camera on desk.
:param degrees: degrees of the desired move
:return: -1 on invalid commands or move amount
"""
return self._cam_ptz_step(command=6, degrees=degrees)
def start_patrol(self, vert=False, horiz=False):
"""
:param vert: Setting to True enables veritcal patrol mode
:param horiz: Setting to True enables horizontal patrol mode
"""
if vert:
self._query_camera('decoder_control.cgi?command=26')
if horiz:
self._query_camera('decoder_control.cgi?command=28')
def stop_patrol(self, vert=False, horiz=False):
"""
:param vert: Setting to True stops veritcal patrol mode
:param horiz: Setting to True stops horizontal patrol mode
"""
if vert:
self._query_camera('decoder_control.cgi?command=27')
if horiz:
self._query_camera('decoder_control.cgi?command=29')
def set_preset(self, preset_num=1):
""" Sets the non-volatile preset indicated to the current PTZ position
:param preset_num: location 1-8 for presets
:return: -1 on failure otherwise the urllib2 response
"""
if 0 > preset_num > 8:
# Invalid preset #
return -1
# commands 30..45 alternate set preset #, goto preset# starting at command 30
command = (preset_num * 2 - 2) + 30
self._query_camera('decoder_control.cgi?command={0}'.format(command))
def goto_preset(self, preset_num=1):
""" Moves the PTZ to the non-volatile preset indicated
:param preset_num: location 1-8 for presets
:return: -1 on failure otherwise the urllib2 response
"""
if 0 > preset_num > 8:
# Invalid preset #
return -1
# commands 30..45 alternate set preset #, goto preset# starting at command 30
command = (preset_num * 2 - 1) + 30
self._query_camera('decoder_control.cgi?command={0}'.format(command))
if __name__ == "__main__":
print("pyFoscam: import this module to use it")