Addind Common class for common ressources

Python2:
- Adding Common class for common ressources
- Inheritance from Common to HomeSFR and Sensors (and it's inherited class Camera)
- Adding the Sensors.get_mac () method
- Adding the Camera.get_snapshot () method
- Addind str2bytes () function for Python3 code compatibility (this library and the Python3 ones are quite identical)

Python3:
- Adding Common class for common ressources
- Inheritance from Common to HomeSFR and Sensors (and it's inherited class Camera)
- Adding the Sensors.get_mac () method
- Adding the Camera.get_snapshot () method
- Addind str2bytes () function for Python2 code compatibility (this library and the Python2 ones are quite identical)
- Changing all "readall" to "read", the method "readall" does not seem to exist in Python2, from what I tested, there's no problem with it
This commit is contained in:
Sasha MOREL 2016-05-25 17:19:16 +02:00
parent 4c6063cd8c
commit c5d531eb10
2 changed files with 380 additions and 226 deletions

View File

@ -34,6 +34,7 @@ REMOTE_CONTROLER = 'REMOTE'
KEYPAD_CONTROLER = 'KEYPAD' KEYPAD_CONTROLER = 'KEYPAD'
PRESENCE_CAMERA_DETECTOR = 'PIR_CAMERA' PRESENCE_CAMERA_DETECTOR = 'PIR_CAMERA'
# This part of code must be the one to adapt to make work the underneath part
from cookielib import CookieJar from cookielib import CookieJar
import urllib2 as request import urllib2 as request
from urllib2 import HTTPError from urllib2 import HTTPError
@ -41,28 +42,119 @@ from urllib import urlencode
from xml.etree import ElementTree as ET from xml.etree import ElementTree as ET
from datetime import datetime from datetime import datetime
def bytes2file (b): # Python2 and 3 adaptations
# BEGIN
def str2bytes (s):
''' '''
Gives a file-like class from a Bytes Bind to the bytes build-in function
''' '''
from io import BytesIO return (bytes (s))
r = BytesIO () # END
r.write (b)
r.seek (0)
return (r)
def bytes2image (b): # The next must stay a copy from the python3 library, starting from class Common
'''
Gives a Image object from bytes
Uses the bytes2file function
'''
from PIL import Image
f = bytes2file (b)
r = Image ()
r.open (f)
return (r)
class HomeSFR (): class Common ():
'''
Common ressources to the library's classes
'''
def __init__ (self):
# Specific configuration
self.base_url = 'https://home.sfr.fr'
# path to login test
self.auth_path = '/mysensors'
self.auth_ok = '/accueil' # if logged
self.auth_post_url = 'https://boutique.home.sfr.fr/authentification'
self.auth_referer = 'https://boutique.home.sfr.fr/authentification?back=service'
self.auth_user_field = 'email'
self.auth_pass_field = 'passwd'
self.auth_extra_fields = {'back': 'service', 'token_sso': '', 'error_sso': '', 'SubmitLogin': 'OK'}
self.auth_logout_path = '/deconnexion'
# Path to sensors and mode
self.sensors_list = '/mysensors'
# Path to list of alerts
self.alerts_path = '/listalert'
# Path to get and set modes
self.mode_get_path = '/mysensors'
self.mode_get_label = 'alarm_mode'
self.mode_set_path = '/alarmmode'
self.mode_set_field = 'action' # Name for GET field
self.mode_off = 'OFF' # Value for off
self.mode_custom = 'CUSTOM' # Value for custom
self.mode_on = 'ON' # Value for on
# Cameras
self.cameras_list = '/homescope/mycams'
self.camera_snapshot = '/homescope/snapshot'
self.camera_snapshot_mac = 'mac'
self.camera_video = '/homescope/flv'
self.camera_vide_mac = 'mac'
self.camera_recordings_list = '/listenr'
self.camera_recordings_delete = '/delenr'
self.camera_recordings_start = '/homescope/record'
self.camera_recordings_stop = '/homescope/stoprecord'
self.camera_recordings_mac = 'mac'
self.camera_get_config_path = '/homescope/camsettings'
self.camera_get_config_mac = 'mac'
self.camera_get_config_flip = 'FLIP'
self.camera_get_config_leds = 'LEDMODE' # set to 0 to turn the leds on
self.camera_get_config_detectionsensibility = 'DP' # from 1 to 4
self.camera_get_config_recording = 'REC24'
self.camera_get_config_name = 'NAME'
self.camera_set_config_path = '/homescope/camsettings'
self.camera_set_config_mac = 'mac'
self.camera_set_config_flip = 'flip'
self.camera_set_config_leds = 'led_mode' # set to 0 to turn the leds on
self.camera_set_config_detectionsensibility = 'dp' # from 1 to 4
self.camera_set_config_recording = 'rec24'
self.camera_set_config_name = 'name'
# Sensors
self.sensors_list = '/mysensors'
self.sensors_label = 'Sensor'
self.sensors_label_id = 'id'
self.sensors_mac_field = 'deviceMac'
self.sensors_type_field = 'deviceType'
self.sensors_model_field = 'deviceModel'
self.sensors_version_field = 'deviceVersion'
self.sensors_name_field = 'name'
self.sensors_longname_field = 'long_name'
self.sensors_namegender_field = 'name_gender' # Only usefull for French for the moment
self.sensors_batterylevel_field = 'batteryLevel'
self.sensors_signal_field = 'signalLevel'
self.sensors_lasttrigger_field = 'lastTriggerTime'
self.sensors_lasttrigger_dateformat = '%Y-%m-%d %H:%M:%S'
self.sensors_status_field = 'status'
self.sensors_status_value_ok = 'OK'
# I don't have any other value for the moment
def bytes2file (self, b):
'''
Gives a file-like class from a Bytes
'''
from io import BytesIO
r = BytesIO ()
r.write (b)
r.seek (0)
return (r)
def bytes2image (self, b):
'''
Gives a Image object from bytes
Uses the bytes2file function
'''
from PIL import Image
f = self.bytes2file (b)
r = Image.open (f)
return (r)
class HomeSFR (Common):
def __init__ (self, username = None, password = None, cookies = None, debug = False, autologin = True): def __init__ (self, username = None, password = None, cookies = None, debug = False, autologin = True):
''' '''
Sets the class with username and password couple, or cookies Sets the class with username and password couple, or cookies
@ -71,6 +163,7 @@ class HomeSFR ():
The autologin parameter defines if the class will manage the login by itself, if False, the user must call login () to login and test_login () to check the login The autologin parameter defines if the class will manage the login by itself, if False, the user must call login () to login and test_login () to check the login
The autologin paramater will always be False if no username and password are defined, and the login () method will always return False The autologin paramater will always be False if no username and password are defined, and the login () method will always return False
''' '''
Common.__init__ (self)
self.DEBUG = debug self.DEBUG = debug
if self.DEBUG: if self.DEBUG:
print (name + ' ' + version) print (name + ' ' + version)
@ -97,49 +190,7 @@ class HomeSFR ():
else: else:
self.cookies = cookies self.cookies = cookies
self.opener = request.build_opener (request.HTTPCookieProcessor (self.cookies)) self.opener = request.build_opener (request.HTTPCookieProcessor (self.cookies))
# Specific configuration
self.base_url = 'https://home.sfr.fr'
# path to login test
self.auth_path = '/mysensors'
self.auth_ok = '/accueil' # if logged
self.auth_post_url = 'https://boutique.home.sfr.fr/authentification'
self.auth_referer = 'https://boutique.home.sfr.fr/authentification?back=service'
self.auth_user_field = 'email'
self.auth_pass_field = 'passwd'
self.auth_extra_fields = {'back': 'service', 'token_sso': '', 'error_sso': '', 'SubmitLogin': 'OK'}
self.auth_logout_path = '/deconnexion'
# Path to sensors and mode
self.sensors_list = '/mysensors'
self.sensors_label = 'Sensor'
self.sensors_label_id = 'id'
# Path to list of alerts
self.alerts_path = '/listalert'
# Path to get and set modes
self.mode_get_path = '/mysensors'
self.mode_get_label = 'alarm_mode'
self.mode_set_path = '/alarmmode'
self.mode_set_field = 'action' # Name for GET field
self.mode_off = 'OFF' # Value for off
self.mode_custom = 'CUSTOM' # Value for custom
self.mode_on = 'ON' # Value for on
# Cameras
# mac=00:0e:8f:c9:59:44&flip=0&led_mode=0&alert_pan=1&rec24=0&da=1&dp=4&name=Salon
self.cameras_list = '/homescope/mycams'
self.camera_snapshot = '/homescope/snapshot'
self.camera_video = '/homescope/flv'
self.camera_get_config_path = '/homescope/camsettings'
self.camera_set_config_path = '/homescope/camsettings'
self.camera_set_config_mac = 'mac'
self.camera_set_config_flip = 'flip'
self.camera_set_config_leds = 'led_mode' # set to 0 to turn the leds on
self.camera_set_config_detectionsensibility = 'dp' # from 1 to 4,
def __str__ (self): def __str__ (self):
''' '''
Shows name, version, defined user and debug state Shows name, version, defined user and debug state
@ -178,7 +229,7 @@ class HomeSFR ():
data = self.auth_extra_fields data = self.auth_extra_fields
data [self.auth_user_field] = self.username data [self.auth_user_field] = self.username
data [self.auth_pass_field] = self.password data [self.auth_pass_field] = self.password
data = bytes (urlencode (data)) data = str2bytes (urlencode (data))
if self.DEBUG: if self.DEBUG:
print ('Cookies ' + str( len(self.cookies))) print ('Cookies ' + str( len(self.cookies)))
print ('Sending data ' + str (data)) print ('Sending data ' + str (data))
@ -243,7 +294,7 @@ class HomeSFR ():
r = self.base_url + self.mode_get_path r = self.base_url + self.mode_get_path
if self.DEBUG: if self.DEBUG:
print ('Getting ' + r) print ('Getting ' + r)
a = bytes2file (self.opener.open (r).read ()) a = self.bytes2file (self.opener.open (r).read ())
b = ET.parse (a).getroot () b = ET.parse (a).getroot ()
c = b.get (self.mode_get_label) c = b.get (self.mode_get_label)
if self.DEBUG: if self.DEBUG:
@ -263,7 +314,7 @@ class HomeSFR ():
if (self.autologin and self.test_login () == False): if (self.autologin and self.test_login () == False):
self.login () self.login ()
r = self.base_url + self.sensors_list r = self.base_url + self.sensors_list
a = bytes2file (self.opener.open (r).read ()) a = self.bytes2file (self.opener.open (r).read ())
b = ET.parse (a) b = ET.parse (a)
r = [] r = []
for i in b.findall (self.sensors_label): for i in b.findall (self.sensors_label):
@ -275,29 +326,11 @@ class HomeSFR ():
Returns a Sensor object for the sensor id or None if sensor is not found Returns a Sensor object for the sensor id or None if sensor is not found
The available ids can be got from the list_sensors method The available ids can be got from the list_sensors method
''' '''
def build_tree (element):
r = {}
if self.DEBUG:
print ('Diving in the element ' + element.tag)
for i in element.getchildren ():
if i.getchildren () == []:
r.update ({i.tag: i.text})
else:
r.update ({i.tag: build_tree (i)})
return (r)
if (self.autologin and self.test_login () == False): if (self.autologin and self.test_login () == False):
self.login () self.login ()
r = self.base_url + self.sensors_list r = Sensor (id, self.opener)
a = bytes2file (self.opener.open (r).read ()) r.refresh ()
b = ET.parse (a) return (r)
r = None
for i in b.findall (self.sensors_label):
if self.DEBUG:
print ('Testing sensors ' + i.get (self.sensors_label_id))
if (i.get (self.sensors_label_id) == id):
r = build_tree (i)
break
return (Sensor (r))
def get_all_sensors (self): def get_all_sensors (self):
''' '''
@ -307,32 +340,52 @@ class HomeSFR ():
for i in self.list_sensors (): for i in self.list_sensors ():
r.append (self.get_sensor (i)) r.append (self.get_sensor (i))
return (tuple (r)) return (tuple (r))
def get_camera (self, id):
'''
Get a Camera object from the sensor's id
'''
if (self.autologin and self.test_login () == False):
self.login ()
r = Camera (id, self.opener)
r.refresh ()
return (r)
class Sensor: class Sensor (Common):
''' '''
Class used to read easily the sensors Class used to read easily the sensors
''' '''
def __init__ (self, sensor_dict): def __init__ (self, id, opener):
''' '''
Initialize the class with the dict producted by HomeSFR.get_sensors () Initialize the class with the dict producted by HomeSFR.get_sensors ()
''' '''
Common.__init__ (self)
self.sensor_dict = sensor_dict self.id = id
self.sensor_dict = None
# Field names self.opener = opener
self.type_field = 'deviceType'
self.model_field = 'deviceModel' def refresh (self):
self.version_field = 'deviceVersion' '''
self.name_field = 'name' Gets or refresh the data for the sensor
self.longname_field = 'long_name' '''
self.namegender_field = 'name_gender' # Only usefull for French for the moment def build_tree (element):
self.batterylevel_field = 'batteryLevel' r = {}
self.signal_field = 'signalLevel' for i in element.getchildren ():
self.lasttrigger_field = 'lastTriggerTime' if i.getchildren () == []:
self.lasttrigger_dateformat = '%Y-%m-%d %H:%M:%S' r.update ({i.tag: i.text})
self.status_field = 'status' else:
self.status_value_ok = 'OK' r.update ({i.tag: build_tree (i)})
# I don't have any other value for the moment return (r)
r = self.base_url + self.sensors_list
a = self.bytes2file (self.opener.open (r).read ())
a.seek (0)
b = ET.parse (a)
self.sensor_dict = None
for i in b.findall (self.sensors_label):
if (i.get (self.sensors_label_id) == self.id):
self.sensor_dict = build_tree (i)
break
def get_raw (self): def get_raw (self):
''' '''
@ -340,72 +393,97 @@ class Sensor:
''' '''
return (self.sensor_dict) return (self.sensor_dict)
def get_mac (self):
'''
Returns the sensor's model, if any, None either
'''
return (self.sensor_dict [self.sensors_mac_field])
def get_type (self): def get_type (self):
''' '''
Returns the sensor's type Returns the sensor's type
''' '''
return (self.sensor_dict [self.type_field]) return (self.sensor_dict [self.sensors_type_field])
def get_model (self): def get_model (self):
''' '''
Returns the sensor's model, if any, None either Returns the sensor's model, if any, None either
''' '''
return (self.sensor_dict [self.model_field]) return (self.sensor_dict [self.sensors_model_field])
def get_version (self): def get_version (self):
''' '''
Returns the sensor's version Returns the sensor's version
''' '''
return (self.sensor_dict [self.version_field]) return (self.sensor_dict [self.sensors_version_field])
def get_name (self): def get_name (self):
''' '''
Returns the sensor's name Returns the sensor's name
''' '''
return (self.sensor_dict [self.name_field]) return (self.sensor_dict [self.sensors_name_field])
def get_longname (self): def get_longname (self):
''' '''
Returns the sensor's type name in system's language and the sensor's name Returns the sensor's type name in system's language and the sensor's name
''' '''
return (self.sensor_dict [self.longname_field]) return (self.sensor_dict [self.sensors_longname_field])
def get_namegender (self): def get_namegender (self):
''' '''
Return M for male and F for female. Return M for male and F for female.
Only usefull for languages with gender on nouns Only usefull for languages with gender on nouns
''' '''
return (self.sensor_dict [self.namegender_field]) return (self.sensor_dict [self.sensors_namegender_field])
def get_batterylevel (self): def get_batterylevel (self):
''' '''
Returns the sensor's battery level, out of 10 Returns the sensor's battery level, out of 10
It seems that batteryless sensors return 255 It seems that batteryless sensors return 255
''' '''
return (int (self.sensor_dict [self.batterylevel_field])) return (int (self.sensor_dict [self.sensors_batterylevel_field]))
def get_signal (self): def get_signal (self):
''' '''
Returns the sensor's signal quality, out of 10 Returns the sensor's signal quality, out of 10
''' '''
return (int (self.sensor_dict [self.signal_field])) return (int (self.sensor_dict [self.sensors_signal_field]))
def get_lasttrigger (self): def get_lasttrigger (self):
''' '''
Return the timestamp of the sensor's last triger Return the timestamp of the sensor's last triger
The sensors always trigger, even when the alarm's mode is off The sensors always trigger, even when the alarm's mode is off
''' '''
a = self.sensor_dict [self.lasttrigger_field] a = self.sensor_dict [self.sensors_lasttrigger_field]
# Try because camera return the date '0000-00-00 00:00:00' that is ununderstandable # Try because camera return the date '0000-00-00 00:00:00' that is ununderstandable
try: try:
b = datetime.strptime (a, self.lasttrigger_dateformat) b = datetime.strptime (a, self.sensors_lasttrigger_dateformat)
except ValueError: except ValueError:
return (0) return (0)
r = int (b.strftime ('%s')) r = int (b.timestamp ())
return (r) return (r)
def get_status (self): def get_status (self):
''' '''
Returns True is the sensor is OK, False either Returns True is the sensor is OK, False either
''' '''
return (self.sensor_dict [self.status_field] == self.status_value_ok) return (self.sensor_dict [self.sensors_status_field] == self.sensors_status_value_ok)
class Camera (Sensor):
'''
Class used to manipulate easily cameras
'''
def __init__ (self, sensor_dict, opener):
'''
Initialize the class with the dict producted by HomeSFR.get_camera ()
'''
Sensor.__init__ (self, sensor_dict, opener)
def get_snapshot (self):
'''
Get a snapshot from the camera
Return a PIL.Image object
'''
r = self.base_url + self.camera_snapshot + '?' + self.camera_snapshot_mac + '=' + self.get_mac ()
a = self.bytes2image (self.opener.open (r).read ())
return (a)

View File

@ -7,6 +7,7 @@ This is a wrap aroud website, this could stop working without prior notice
''' '''
# TODO: # TODO:
## Put common ressources in the Common class
## Manage cameras ## Manage cameras
### Get image ### Get image
### Get video ### Get video
@ -39,28 +40,117 @@ from xml.etree import ElementTree as ET
from urllib.error import HTTPError from urllib.error import HTTPError
from datetime import datetime from datetime import datetime
def bytes2file (b): # Python2 and 3 adaptations
# BEGIN
def str2bytes (s):
''' '''
Gives a file-like class from a Bytes Bind to the bytes build-in function
''' '''
from io import BytesIO return (bytes (s, 'UTF8'))
r = BytesIO () # END
r.write (b)
r.seek (0)
return (r)
def bytes2image (b): class Common ():
''' '''
Gives a Image object from bytes Common ressources to the library's classes
Uses the bytes2file function
''' '''
from PIL import Image
f = bytes2file (b) def __init__ (self):
r = Image ()
r.open (f) # Specific configuration
return (r)
self.base_url = 'https://home.sfr.fr'
# path to login test
self.auth_path = '/mysensors'
self.auth_ok = '/accueil' # if logged
self.auth_post_url = 'https://boutique.home.sfr.fr/authentification'
self.auth_referer = 'https://boutique.home.sfr.fr/authentification?back=service'
self.auth_user_field = 'email'
self.auth_pass_field = 'passwd'
self.auth_extra_fields = {'back': 'service', 'token_sso': '', 'error_sso': '', 'SubmitLogin': 'OK'}
self.auth_logout_path = '/deconnexion'
# Path to sensors and mode
self.sensors_list = '/mysensors'
# Path to list of alerts
self.alerts_path = '/listalert'
# Path to get and set modes
self.mode_get_path = '/mysensors'
self.mode_get_label = 'alarm_mode'
self.mode_set_path = '/alarmmode'
self.mode_set_field = 'action' # Name for GET field
self.mode_off = 'OFF' # Value for off
self.mode_custom = 'CUSTOM' # Value for custom
self.mode_on = 'ON' # Value for on
# Cameras
self.cameras_list = '/homescope/mycams'
self.camera_snapshot = '/homescope/snapshot'
self.camera_snapshot_mac = 'mac'
self.camera_video = '/homescope/flv'
self.camera_vide_mac = 'mac'
self.camera_recordings_list = '/listenr'
self.camera_recordings_delete = '/delenr'
self.camera_recordings_start = '/homescope/record'
self.camera_recordings_stop = '/homescope/stoprecord'
self.camera_recordings_mac = 'mac'
self.camera_get_config_path = '/homescope/camsettings'
self.camera_get_config_mac = 'mac'
self.camera_get_config_flip = 'FLIP'
self.camera_get_config_leds = 'LEDMODE' # set to 0 to turn the leds on
self.camera_get_config_detectionsensibility = 'DP' # from 1 to 4
self.camera_get_config_recording = 'REC24'
self.camera_get_config_name = 'NAME'
self.camera_set_config_path = '/homescope/camsettings'
self.camera_set_config_mac = 'mac'
self.camera_set_config_flip = 'flip'
self.camera_set_config_leds = 'led_mode' # set to 0 to turn the leds on
self.camera_set_config_detectionsensibility = 'dp' # from 1 to 4
self.camera_set_config_recording = 'rec24'
self.camera_set_config_name = 'name'
# Sensors
self.sensors_list = '/mysensors'
self.sensors_label = 'Sensor'
self.sensors_label_id = 'id'
self.sensors_mac_field = 'deviceMac'
self.sensors_type_field = 'deviceType'
self.sensors_model_field = 'deviceModel'
self.sensors_version_field = 'deviceVersion'
self.sensors_name_field = 'name'
self.sensors_longname_field = 'long_name'
self.sensors_namegender_field = 'name_gender' # Only usefull for French for the moment
self.sensors_batterylevel_field = 'batteryLevel'
self.sensors_signal_field = 'signalLevel'
self.sensors_lasttrigger_field = 'lastTriggerTime'
self.sensors_lasttrigger_dateformat = '%Y-%m-%d %H:%M:%S'
self.sensors_status_field = 'status'
self.sensors_status_value_ok = 'OK'
# I don't have any other value for the moment
class HomeSFR (): def bytes2file (self, b):
'''
Gives a file-like class from a Bytes
'''
from io import BytesIO
r = BytesIO ()
r.write (b)
r.seek (0)
return (r)
def bytes2image (self, b):
'''
Gives a Image object from bytes
Uses the bytes2file function
'''
from PIL import Image
f = self.bytes2file (b)
r = Image.open (f)
return (r)
class HomeSFR (Common):
def __init__ (self, username = None, password = None, cookies = None, debug = False, autologin = True): def __init__ (self, username = None, password = None, cookies = None, debug = False, autologin = True):
''' '''
Sets the class with username and password couple, or cookies Sets the class with username and password couple, or cookies
@ -69,6 +159,7 @@ class HomeSFR ():
The autologin parameter defines if the class will manage the login by itself, if False, the user must call login () to login and test_login () to check the login The autologin parameter defines if the class will manage the login by itself, if False, the user must call login () to login and test_login () to check the login
The autologin paramater will always be False if no username and password are defined, and the login () method will always return False The autologin paramater will always be False if no username and password are defined, and the login () method will always return False
''' '''
Common.__init__ (self)
self.DEBUG = debug self.DEBUG = debug
if self.DEBUG: if self.DEBUG:
print (name + ' ' + version) print (name + ' ' + version)
@ -95,48 +186,6 @@ class HomeSFR ():
else: else:
self.cookies = cookies self.cookies = cookies
self.opener = request.build_opener (request.HTTPCookieProcessor (self.cookies)) self.opener = request.build_opener (request.HTTPCookieProcessor (self.cookies))
# Specific configuration
self.base_url = 'https://home.sfr.fr'
# path to login test
self.auth_path = '/mysensors'
self.auth_ok = '/accueil' # if logged
self.auth_post_url = 'https://boutique.home.sfr.fr/authentification'
self.auth_referer = 'https://boutique.home.sfr.fr/authentification?back=service'
self.auth_user_field = 'email'
self.auth_pass_field = 'passwd'
self.auth_extra_fields = {'back': 'service', 'token_sso': '', 'error_sso': '', 'SubmitLogin': 'OK'}
self.auth_logout_path = '/deconnexion'
# Path to sensors and mode
self.sensors_list = '/mysensors'
self.sensors_label = 'Sensor'
self.sensors_label_id = 'id'
# Path to list of alerts
self.alerts_path = '/listalert'
# Path to get and set modes
self.mode_get_path = '/mysensors'
self.mode_get_label = 'alarm_mode'
self.mode_set_path = '/alarmmode'
self.mode_set_field = 'action' # Name for GET field
self.mode_off = 'OFF' # Value for off
self.mode_custom = 'CUSTOM' # Value for custom
self.mode_on = 'ON' # Value for on
# Cameras
# mac=00:0e:8f:c9:59:44&flip=0&led_mode=0&alert_pan=1&rec24=0&da=1&dp=4&name=Salon
self.cameras_list = '/homescope/mycams'
self.camera_snapshot = '/homescope/snapshot'
self.camera_video = '/homescope/flv'
self.camera_get_config_path = '/homescope/camsettings'
self.camera_set_config_path = '/homescope/camsettings'
self.camera_set_config_mac = 'mac'
self.camera_set_config_flip = 'flip'
self.camera_set_config_leds = 'led_mode' # set to 0 to turn the leds on
self.camera_set_config_detectionsensibility = 'dp' # from 1 to 4,
def __str__ (self): def __str__ (self):
''' '''
@ -176,7 +225,7 @@ class HomeSFR ():
data = self.auth_extra_fields data = self.auth_extra_fields
data [self.auth_user_field] = self.username data [self.auth_user_field] = self.username
data [self.auth_pass_field] = self.password data [self.auth_pass_field] = self.password
data = bytes (urlencode (data), 'UTF8') data = str2bytes (urlencode (data))
if self.DEBUG: if self.DEBUG:
print ('Cookies ' + str( len(self.cookies))) print ('Cookies ' + str( len(self.cookies)))
print ('Sending data ' + str (data)) print ('Sending data ' + str (data))
@ -241,7 +290,7 @@ class HomeSFR ():
r = self.base_url + self.mode_get_path r = self.base_url + self.mode_get_path
if self.DEBUG: if self.DEBUG:
print ('Getting ' + r) print ('Getting ' + r)
a = bytes2file (self.opener.open (r).readall ()) a = self.bytes2file (self.opener.open (r).read ())
b = ET.parse (a).getroot () b = ET.parse (a).getroot ()
c = b.get (self.mode_get_label) c = b.get (self.mode_get_label)
if self.DEBUG: if self.DEBUG:
@ -261,7 +310,7 @@ class HomeSFR ():
if (self.autologin and self.test_login () == False): if (self.autologin and self.test_login () == False):
self.login () self.login ()
r = self.base_url + self.sensors_list r = self.base_url + self.sensors_list
a = bytes2file (self.opener.open (r).readall ()) a = self.bytes2file (self.opener.open (r).read ())
b = ET.parse (a) b = ET.parse (a)
r = [] r = []
for i in b.findall (self.sensors_label): for i in b.findall (self.sensors_label):
@ -273,29 +322,11 @@ class HomeSFR ():
Returns a Sensor object for the sensor id or None if sensor is not found Returns a Sensor object for the sensor id or None if sensor is not found
The available ids can be got from the list_sensors method The available ids can be got from the list_sensors method
''' '''
def build_tree (element):
r = {}
if self.DEBUG:
print ('Diving in the element ' + element.tag)
for i in element.getchildren ():
if i.getchildren () == []:
r.update ({i.tag: i.text})
else:
r.update ({i.tag: build_tree (i)})
return (r)
if (self.autologin and self.test_login () == False): if (self.autologin and self.test_login () == False):
self.login () self.login ()
r = self.base_url + self.sensors_list r = Sensor (id, self.opener)
a = bytes2file (self.opener.open (r).readall ()) r.refresh ()
b = ET.parse (a) return (r)
r = None
for i in b.findall (self.sensors_label):
if self.DEBUG:
print ('Testing sensors ' + i.get (self.sensors_label_id))
if (i.get (self.sensors_label_id) == id):
r = build_tree (i)
break
return (Sensor (r))
def get_all_sensors (self): def get_all_sensors (self):
''' '''
@ -305,32 +336,52 @@ class HomeSFR ():
for i in self.list_sensors (): for i in self.list_sensors ():
r.append (self.get_sensor (i)) r.append (self.get_sensor (i))
return (tuple (r)) return (tuple (r))
def get_camera (self, id):
'''
Get a Camera object from the sensor's id
'''
if (self.autologin and self.test_login () == False):
self.login ()
r = Camera (id, self.opener)
r.refresh ()
return (r)
class Sensor: class Sensor (Common):
''' '''
Class used to read easily the sensors Class used to read easily the sensors
''' '''
def __init__ (self, sensor_dict): def __init__ (self, id, opener):
''' '''
Initialize the class with the dict producted by HomeSFR.get_sensors () Initialize the class with the dict producted by HomeSFR.get_sensors ()
''' '''
Common.__init__ (self)
self.sensor_dict = sensor_dict self.id = id
self.sensor_dict = None
# Field names self.opener = opener
self.type_field = 'deviceType'
self.model_field = 'deviceModel' def refresh (self):
self.version_field = 'deviceVersion' '''
self.name_field = 'name' Gets or refresh the data for the sensor
self.longname_field = 'long_name' '''
self.namegender_field = 'name_gender' # Only usefull for French for the moment def build_tree (element):
self.batterylevel_field = 'batteryLevel' r = {}
self.signal_field = 'signalLevel' for i in element.getchildren ():
self.lasttrigger_field = 'lastTriggerTime' if i.getchildren () == []:
self.lasttrigger_dateformat = '%Y-%m-%d %H:%M:%S' r.update ({i.tag: i.text})
self.status_field = 'status' else:
self.status_value_ok = 'OK' r.update ({i.tag: build_tree (i)})
# I don't have any other value for the moment return (r)
r = self.base_url + self.sensors_list
a = self.bytes2file (self.opener.open (r).read ())
a.seek (0)
b = ET.parse (a)
self.sensor_dict = None
for i in b.findall (self.sensors_label):
if (i.get (self.sensors_label_id) == self.id):
self.sensor_dict = build_tree (i)
break
def get_raw (self): def get_raw (self):
''' '''
@ -338,65 +389,71 @@ class Sensor:
''' '''
return (self.sensor_dict) return (self.sensor_dict)
def get_mac (self):
'''
Returns the sensor's model, if any, None either
'''
return (self.sensor_dict [self.sensors_mac_field])
def get_type (self): def get_type (self):
''' '''
Returns the sensor's type Returns the sensor's type
''' '''
return (self.sensor_dict [self.type_field]) return (self.sensor_dict [self.sensors_type_field])
def get_model (self): def get_model (self):
''' '''
Returns the sensor's model, if any, None either Returns the sensor's model, if any, None either
''' '''
return (self.sensor_dict [self.model_field]) return (self.sensor_dict [self.sensors_model_field])
def get_version (self): def get_version (self):
''' '''
Returns the sensor's version Returns the sensor's version
''' '''
return (self.sensor_dict [self.version_field]) return (self.sensor_dict [self.sensors_version_field])
def get_name (self): def get_name (self):
''' '''
Returns the sensor's name Returns the sensor's name
''' '''
return (self.sensor_dict [self.name_field]) return (self.sensor_dict [self.sensors_name_field])
def get_longname (self): def get_longname (self):
''' '''
Returns the sensor's type name in system's language and the sensor's name Returns the sensor's type name in system's language and the sensor's name
''' '''
return (self.sensor_dict [self.longname_field]) return (self.sensor_dict [self.sensors_longname_field])
def get_namegender (self): def get_namegender (self):
''' '''
Return M for male and F for female. Return M for male and F for female.
Only usefull for languages with gender on nouns Only usefull for languages with gender on nouns
''' '''
return (self.sensor_dict [self.namegender_field]) return (self.sensor_dict [self.sensors_namegender_field])
def get_batterylevel (self): def get_batterylevel (self):
''' '''
Returns the sensor's battery level, out of 10 Returns the sensor's battery level, out of 10
It seems that batteryless sensors return 255 It seems that batteryless sensors return 255
''' '''
return (int (self.sensor_dict [self.batterylevel_field])) return (int (self.sensor_dict [self.sensors_batterylevel_field]))
def get_signal (self): def get_signal (self):
''' '''
Returns the sensor's signal quality, out of 10 Returns the sensor's signal quality, out of 10
''' '''
return (int (self.sensor_dict [self.signal_field])) return (int (self.sensor_dict [self.sensors_signal_field]))
def get_lasttrigger (self): def get_lasttrigger (self):
''' '''
Return the timestamp of the sensor's last triger Return the timestamp of the sensor's last triger
The sensors always trigger, even when the alarm's mode is off The sensors always trigger, even when the alarm's mode is off
''' '''
a = self.sensor_dict [self.lasttrigger_field] a = self.sensor_dict [self.sensors_lasttrigger_field]
# Try because camera return the date '0000-00-00 00:00:00' that is ununderstandable # Try because camera return the date '0000-00-00 00:00:00' that is ununderstandable
try: try:
b = datetime.strptime (a, self.lasttrigger_dateformat) b = datetime.strptime (a, self.sensors_lasttrigger_dateformat)
except ValueError: except ValueError:
return (0) return (0)
r = int (b.timestamp ()) r = int (b.timestamp ())
@ -406,4 +463,23 @@ class Sensor:
''' '''
Returns True is the sensor is OK, False either Returns True is the sensor is OK, False either
''' '''
return (self.sensor_dict [self.status_field] == self.status_value_ok) return (self.sensor_dict [self.sensors_status_field] == self.sensors_status_value_ok)
class Camera (Sensor):
'''
Class used to manipulate easily cameras
'''
def __init__ (self, sensor_dict, opener):
'''
Initialize the class with the dict producted by HomeSFR.get_camera ()
'''
Sensor.__init__ (self, sensor_dict, opener)
def get_snapshot (self):
'''
Get a snapshot from the camera
Return a PIL.Image object
'''
r = self.base_url + self.camera_snapshot + '?' + self.camera_snapshot_mac + '=' + self.get_mac ()
a = self.bytes2image (self.opener.open (r).read ())
return (a)