8 Commits

Author SHA1 Message Date
Gilles MOREL
72e1c94a80 Traduction du README en français
Cette bibliothèque ne sert que pour un service français fourni en France.
2020-09-27 15:22:55 +02:00
Gilles MOREL
8fb1eac749 Correction du style 2020-09-26 07:55:57 +02:00
Gilles MOREL
b338230b37 Récupération des paramètres de la caméra
J'ai aussi enlevé la classe Camera pour intégrer les méthodes dans la classe Sensor.
2020-09-26 07:51:52 +02:00
Gilles MOREL
f5e8e4bdf0 Mise à jour de l'authentification 2020-09-20 12:00:45 +02:00
Gilles MOREL
952cf74b8e Passage à la version 1.1 2019-11-23 21:41:27 +01:00
Gilles MOREL
aff562b61b Mise à jour du point d'entrée d'authentification 2019-11-23 21:38:36 +01:00
Gilles MOREL
3f4b3cd1aa Correction du style
Oublis de la validation précédente
2019-01-15 23:02:35 +01:00
Gilles MOREL
92d0f18f3a Correction du style
Le style a été un peu corrigé à l'aide de pycodestyle
2018-02-22 21:29:53 +01:00
2 changed files with 64 additions and 53 deletions

View File

@@ -1,13 +1,13 @@
# What's this? # Qu'est-ce que c'est ?
This is a set of libraries to control your Home by SFR account. Il s'agit d'une bibliothèque qui permet d'accéder au système Home by SFR.
They all work around the website. Le code s'appuie sur les appels fait sur le [site](https://home.sfr.fr). De fait, sa conception a été faite par rétro-ingénérie et peut cesser de fonctionner sans préavis.
# What's Home by SFR? # Qu'est-ce que Home by SFR ?
Home by SFR is a security and automation service provided by the French Internet provider SFR. Home by SFR est un service de sécurité et de domotique fourni par SFR.
The library was only tested for the French version because I don't know if it exists elsewhere Cette bibliothèque ne peut utiliser que le service fourni par SFR en France.
# Licence # Licence
These libraries are under GNU GPL v3. Voir la [licence](LICENSE) pour plus de détails.

View File

@@ -10,11 +10,18 @@ This is a wrap aroud website, this could stop working without prior notice
## Manage cameras ## Manage cameras
### Get video ### Get video
from urllib import request
from http.cookiejar import CookieJar
from urllib.parse import urlencode
from xml.etree import ElementTree as ET
from urllib.error import HTTPError
from datetime import datetime
authors = ( authors = (
'Gilles "Almtesh" Émilien MOREL', 'Gilles "Almtesh" Émilien MOREL',
) )
name = 'homesfr for Python 3' name = 'homesfr for Python 3'
version = '1.0' version = '1.2'
# Settable modes # Settable modes
MODE_OFF = 0 MODE_OFF = 0
@@ -30,12 +37,6 @@ REMOTE_CONTROLER = 'REMOTE'
KEYPAD_CONTROLER = 'KEYPAD' KEYPAD_CONTROLER = 'KEYPAD'
PRESENCE_CAMERA_DETECTOR = 'PIR_CAMERA' PRESENCE_CAMERA_DETECTOR = 'PIR_CAMERA'
from urllib import request
from http.cookiejar import CookieJar
from urllib.parse import urlencode
from xml.etree import ElementTree as ET
from urllib.error import HTTPError
from datetime import datetime
class Common (): class Common ():
''' '''
@@ -50,7 +51,7 @@ class Common ():
# path to login test # path to login test
self.auth_path = '/mysensors' self.auth_path = '/mysensors'
self.auth_ok = '/accueil' # if logged self.auth_ok_url = 'https://home.sfr.fr/logged' # if logged
self.auth_post_url = 'https://boutique.home.sfr.fr/authentification' self.auth_post_url = 'https://boutique.home.sfr.fr/authentification'
self.auth_referer = 'https://boutique.home.sfr.fr/authentification?back=service' self.auth_referer = 'https://boutique.home.sfr.fr/authentification?back=service'
self.auth_user_field = 'email' self.auth_user_field = 'email'
@@ -88,14 +89,15 @@ class Common ():
self.camera_get_config_mac = 'mac' self.camera_get_config_mac = 'mac'
self.camera_get_config_flip = 'FLIP' self.camera_get_config_flip = 'FLIP'
self.camera_get_config_leds = 'LEDMODE' # set to 0 to turn the leds on 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_petmode = 'pet_mode'
self.camera_get_config_recording = 'REC24' self.camera_get_config_recording = 'rec24'
self.camera_get_config_privacy = 'privacy'
self.camera_get_config_name = 'NAME' self.camera_get_config_name = 'NAME'
self.camera_set_config_path = '/homescope/camsettings' self.camera_set_config_path = '/homescope/camsettings'
self.camera_set_config_mac = 'mac' self.camera_set_config_mac = 'mac'
self.camera_set_config_flip = 'flip' 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_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_petmode = 'pet_mode'
self.camera_set_config_recording = 'rec24' self.camera_set_config_recording = 'rec24'
self.camera_set_config_name = 'name' self.camera_set_config_name = 'name'
@@ -142,7 +144,7 @@ class Common ():
r = Image.open (f) r = Image.open (f)
return (r) return (r)
def get_xml_elements (self,url, label, id_label=None): def get_xml_elements (self, url, label, id_label = None):
def build_tree (element): def build_tree (element):
r = {} r = {}
for i in element.getchildren (): for i in element.getchildren ():
@@ -154,7 +156,7 @@ class Common ():
a = self.bytes2file (self.opener.open (url).read ()) a = self.bytes2file (self.opener.open (url).read ())
a.seek (0) a.seek (0)
b = ET.parse (a) b = ET.parse (a)
if id_label == None: if id_label is None:
r = [] r = []
for i in b.findall (label): for i in b.findall (label):
r.append (build_tree (i)) r.append (build_tree (i))
@@ -165,6 +167,7 @@ class Common ():
r.update ({i.get (id_label): build_tree (i)}) r.update ({i.get (id_label): build_tree (i)})
return (r) return (r)
class HomeSFR (Common): 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):
''' '''
@@ -181,22 +184,22 @@ class HomeSFR (Common):
print ('Authors:') print ('Authors:')
for i in authors: for i in authors:
print (' - ' + i) print (' - ' + i)
if username != None: if username is not None:
print ('init with username ' + username) print ('init with username ' + username)
if cookies != None: if cookies is not None:
print ('init with cookies') print ('init with cookies')
print ('debug = ' + str (debug)) print ('debug = ' + str (debug))
print ('autologin = ' + str (autologin)) print ('autologin = ' + str (autologin))
if (username == None or password == None) and cookies == None: if (username is None or password is None) and cookies is None:
raise TypeError ('You must define either username AND password or cookies') raise TypeError ('You must define either username AND password or cookies')
self.username = username self.username = username
self.password = password self.password = password
if self.username != None and self.password != None: if self.username is not None and self.password is not None:
self.autologin = autologin self.autologin = autologin
else: else:
self.autologin = False self.autologin = False
if cookies == None: if cookies is None:
self.cookies = CookieJar () self.cookies = CookieJar ()
elif type (cookies) == CookieJar: elif type (cookies) == CookieJar:
self.cookies = cookies self.cookies = cookies
@@ -208,7 +211,7 @@ class HomeSFR (Common):
''' '''
Shows name, version, defined user and debug state Shows name, version, defined user and debug state
''' '''
if self.username != None: if self.username is not None:
return (name + ' ' + version + '\nUser: ' + self.username + '\nDebug: ' + str (self.DEBUG)) return (name + ' ' + version + '\nUser: ' + self.username + '\nDebug: ' + str (self.DEBUG))
else: else:
return (name + ' ' + version + '\nUser: Unknown (auth from cookie class)\nDebug: ' + str (self.DEBUG)) return (name + ' ' + version + '\nUser: Unknown (auth from cookie class)\nDebug: ' + str (self.DEBUG))
@@ -237,19 +240,19 @@ class HomeSFR (Common):
Returns True if the login was a success, False either Returns True if the login was a success, False either
This method will always return False if no username and password are defined This method will always return False if no username and password are defined
''' '''
if self.username != None and self.password != None: if self.username is not None and self.password is not None:
self.opener.open (self.auth_referer) self.opener.open (self.auth_referer)
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 = bytes (urlencode (data), 'UTF8')
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))
a = self.opener.open (self.auth_post_url, data = data) a = self.opener.open (self.auth_post_url, data = data)
if self.DEBUG: if self.DEBUG:
print ('Auth redirected to ' + a.geturl ()) print ('Auth redirected to ' + a.geturl ())
return (a.geturl () == self.base_url + self.auth_ok) return (a.geturl () == self.auth_ok_url)
else: else:
return (False) return (False)
@@ -257,7 +260,7 @@ class HomeSFR (Common):
''' '''
Trigger the autologin Trigger the autologin
''' '''
if (self.autologin and self.test_login () == False): while (self.autologin and not self.test_login ()):
self.login () self.login ()
def logout (self): def logout (self):
@@ -362,8 +365,6 @@ class HomeSFR (Common):
Get a Camera object from the sensor's id Get a Camera object from the sensor's id
''' '''
self.do_autologin () self.do_autologin ()
if (self.autologin and self.test_login () == False):
self.login ()
r = Camera (id, self.opener) r = Camera (id, self.opener)
r.refresh () r.refresh ()
return (r) return (r)
@@ -376,6 +377,7 @@ class HomeSFR (Common):
a = self.base_url + self.logs_path a = self.base_url + self.logs_path
return (self.get_xml_elements (a, self.logs_labels)) return (self.get_xml_elements (a, self.logs_labels))
class Sensor (Common): class Sensor (Common):
''' '''
Class used to read easily the sensors Class used to read easily the sensors
@@ -481,17 +483,7 @@ class Sensor (Common):
''' '''
return (self.sensor_dict [self.sensors_status_field] == self.sensors_status_value_ok) return (self.sensor_dict [self.sensors_status_field] == self.sensors_status_value_ok)
class Camera (Sensor): def get_camera_snapshot (self):
'''
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 Get a snapshot from the camera
Return a PIL.Image object Return a PIL.Image object
@@ -499,3 +491,22 @@ class Camera (Sensor):
r = self.base_url + self.camera_snapshot + '?' + self.camera_snapshot_mac + '=' + self.get_mac () r = self.base_url + self.camera_snapshot + '?' + self.camera_snapshot_mac + '=' + self.get_mac ()
a = self.bytes2image (self.opener.open (r).read ()) a = self.bytes2image (self.opener.open (r).read ())
return (a) return (a)
def get_camera_petmode (self):
'''
Gets the pet mode value
Pet mode is a setting on movement sensibility, to avoid trigger on pet movements
'''
return (self.sensor_dict [self.camera_get_config_petmode] == '1')
def get_camera_recording (self):
'''
Gets if the camera records or not
'''
return (self.sensor_dict [self.camera_get_config_recording] == '1')
def get_camera_privacy (self):
'''
Gets if the camera records or not
'''
return (self.sensor_dict [self.camera_get_config_privacy] == '1')