diff --git a/README.md b/README.md index c0797d8..a7880d6 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ https://matdomotique.wordpress.com/2018/03/25/plugin-freebox-pour-domoticz/ * Création d'un dispositif par partition de disque dur connecté à la Freebox (disques internes et externes) * Création de 3 dispositifs pour suivre les températures de la Freebox * Création d'un dispositif switch par adresse mac pour laquelle vérifier la présence ou non à proximité de la Freebox. +* Création d'un dispositif switch de suivi et modification de l'état du wifi (Actif/Inactif) +* Création d'un dispositif switch de reboot de la Freebox serveur ## Installation @@ -40,7 +42,7 @@ Laissez les valeur par defaut sur un réseau local, ou configurez votre adresse Ajoutez le Matériel et rendez vous dans les log. Lors de la première utilisation, laissez le token vide. -Au démarrage, si le token n'est pas défini, le plugin en demander un à la Freebox, il vous faut alors vous déplacer jusqu'à l'écran de la Freebox pourrépondre oui, puis revenir sur votre Domoticz pour copier coller le token qui s'affiche dans la fenetre de log, dans la partie Token de confirguration du plugin. +Au démarrage, si le token n'est pas défini, le plugin en demander un à la Freebox, il vous faut alors vous déplacer jusqu'à l'écran de la Freebox pour répondre oui, puis revenir sur votre Domoticz pour copier coller le token qui s'affiche dans la fenetre de log, dans la partie Token de configuration du plugin. Desactivez le plugin, autoriser l'ajout de nouveau dispositif pendant 5 minutes, puis réacivez le plugin pour le faire redemarrer. Les dispositifs vont se créer. @@ -52,6 +54,8 @@ Vous pouvez supprimer ceux qui ne vous interresse pas et inclure ceux qui vous i | Système | Températures de la Freebox et du switch interne | | Disque | Pourcentage d'espace utilisé de chaque partition connectées à la Freebox au moment du démarrage du Plugin avec autorisation d'ajout de dispositifs | | Présence | Pour chaque adresse mac renseignée, si elle est trouvée enregistrée sur la Freebox, un dispositif switch est créé, indiquant la presence (on) ou l'absence (off) du matériel à proximité de la box. Cela permet de tester la presence d'une personne au domicile en vérifiant la presence de sont smartphone par exemple. Cela fonctionne, même avec les Iphones | +| On/Off Wifi | Switch permettant de voir l'état du wifi (actif/Desactivé) et de le modifier | +| Reboot | Switch permettant de rebooter la Freebox | Note : Un fichier ```devicemapping.json``` est créé pour garder l'association des infos de la Freebox avec le bon device créé au moment du démarrage du Plugin. diff --git a/freebox.py b/freebox.py index 9709b76..7e98ec5 100644 --- a/freebox.py +++ b/freebox.py @@ -1,7 +1,8 @@ #Code adapté de http://www.manatlan.com/blog/freeboxv6_api_v3_avec_python -import urllib.request,hmac,json,hashlib,time +import urllib.request,hmac,json,hashlib,time,Domoticz from urllib.request import urlopen,Request +from socket import timeout class FbxCnx: def __init__(self,host="mafreebox.free.fr"): @@ -37,7 +38,35 @@ class FbxCnx: request = Request(url,headers=headers) else: request = Request(url) - res = urlopen(request).read() + res = urlopen(request,timeout=2).read() + return json.loads(res.decode()) + + def _put(self,method,data=None,headers=None): + url = self.host+"/api/v4/"+method + if data: + data = json.dumps(data) #On transforme en string le dict + data = data.encode() #On transforme en tableau de byte le string pour Request + if headers: + request = Request(url,data=data,headers=headers) + else: + request = Request(url, data=data) + request.get_method = lambda:"PUT" + else: + if headers: + request = Request(url,headers=headers) + else: + request = Request(url) + res = urlopen(request,timeout=2).read() + return json.loads(res.decode()) + + def _get(self,method,data=None,headers=None): + url = self.host+"/api/v4/"+method + if headers: + request = Request(url,headers=headers) + else: + request = Request(url) + request.get_method = lambda:"GET" + res = urlopen(request,timeout=2).read() return json.loads(res.decode()) def _mksession(self): @@ -49,9 +78,10 @@ class FbxCnx: return self._com("login/session/",data)["result"]["session_token"] # def _disconnect(self): - # result = self._com("/login/logout",None,{"X-Fbx-App-Auth": self.session}) - # print (result) - # return + # # result = self._com("/login/logout",None,{'Content-Type': 'application/json','X-Fbx-App-Auth': self.session}) + # result = self._com("/login/logout") + # print (result) + # # return class FbxApp(FbxCnx): def __init__(self,appid,token,session=None,host="mafreebox.free.fr"): @@ -60,60 +90,147 @@ class FbxApp(FbxCnx): self.session=session if session else self._mksession() # def __del__(self): - # self._disconnect() - # print ('died') + # self._disconnect() + # print ('died') def com(self,method,data=None): return self._com(method,data,{"X-Fbx-App-Auth": self.session}) + def put(self,method,data=None): + return self._put(method,data,{"X-Fbx-App-Auth": self.session}) + + def get(self,method,data=None): + return self._get(method,data,{"X-Fbx-App-Auth": self.session}) def diskinfo(self): - listDisk = self.com( "storage/disk/") retour = {} - for disk in listDisk["result"]: - for partition in disk["partitions"]: - label = partition["label"] - used =partition["used_bytes"] - total=partition["total_bytes"] - percent = used/total*100 - # print(str(label)+"=>"+str(round(percent,2))+"%") - retour.update({str(label):str(round(percent,2))}) + try: + listDisk = self.com( "storage/disk/") + for disk in listDisk["result"]: + for partition in disk["partitions"]: + label = partition["label"] + used =partition["used_bytes"] + total=partition["total_bytes"] + percent = used/total*100 + # print(str(label)+"=>"+str(round(percent,2))+"%") + retour.update({str(label):str(round(percent,2))}) + except (urllib.error.HTTPError, urllib.error.URLError) as error: + Domoticz.Log('La Freebox semble indisponible : '+ error.msg) + except timeout: + 1 #on ne fait rien, on retourne une liste vide return retour def getNameByMacAdresse(self,p_macAdresse): - listePeriph = self.com( "lan/browser/pub/") - for periph in listePeriph["result"]: - macAdresse = periph["id"] - if(("ether-"+p_macAdresse) == macAdresse): - return periph["primary_name"] + try: + listePeriph = self.com( "lan/browser/pub/") + for periph in listePeriph["result"]: + macAdresse = periph["id"] + if(("ether-"+p_macAdresse) == macAdresse): + return periph["primary_name"] + except (urllib.error.HTTPError, urllib.error.URLError) as error: + Domoticz.Log('La Freebox semble indisponible : '+ error.msg) + except timeout: + return "" def isPresenceByMacAdresse(self,p_macAdresse): - listePeriph = self.com( "lan/browser/pub/") - for periph in listePeriph["result"]: - macAdresse = periph["id"] - if(("ether-"+p_macAdresse) == macAdresse): - reachable = periph["reachable"] - active = periph["active"] - if reachable and active: - return True + try: + listePeriph = self.com( "lan/browser/pub/") + for periph in listePeriph["result"]: + macAdresse = periph["id"] + if(("ether-"+p_macAdresse) == macAdresse): + reachable = periph["reachable"] + active = periph["active"] + if reachable and active: + return True + except (urllib.error.HTTPError, urllib.error.URLError) as error: + Domoticz.Log('La Freebox semble indisponible : '+ error.msg) + except timeout: + 1 #on ne fait rien, on retourne faux return False def lanPeripherique(self): - listePeriph = self.com( "lan/browser/pub/") retour = {} - for periph in listePeriph["result"]: - name = periph["primary_name"] - reachable = periph["reachable"] - active = periph["active"] - macAdresse = periph["id"] - if reachable and active: - retour.update({macAdresse:name}) + try: + listePeriph = self.com( "lan/browser/pub/") + for periph in listePeriph["result"]: + name = periph["primary_name"] + reachable = periph["reachable"] + active = periph["active"] + macAdresse = periph["id"] + if reachable and active: + retour.update({macAdresse:name}) + except (urllib.error.HTTPError, urllib.error.URLError) as error: + Domoticz.Log('La Freebox semble indisponible : '+ error.msg) + except timeout: + 1 #on ne fait rien, on retourne une liste vide return retour def sysinfo(self): - sys = self.com( "system/") retour = {} - retour.update({str('temp_cpub'):str(round(sys["result"]["temp_cpub"],2))}) - retour.update({str('temp_sw'):str(round(sys["result"]["temp_sw"],2))}) - retour.update({str('temp_cpum'):str(round(sys["result"]["temp_cpum"],2))}) + try: + sys = self.com( "system/") + retour.update({str('temp_cpub'):str(round(sys["result"]["temp_cpub"],2))}) + retour.update({str('temp_sw'):str(round(sys["result"]["temp_sw"],2))}) + retour.update({str('temp_cpum'):str(round(sys["result"]["temp_cpum"],2))}) + except (urllib.error.HTTPError, urllib.error.URLError) as error: + Domoticz.Log('La Freebox semble indisponible : '+ error.msg) + except timeout: + 1 #on ne fait rien, on retourne une liste vide return retour + + def isOnWIFI(self): + try: + v_result = self.get("wifi/config/") + if(v_result["result"]["enabled"]): + return 1 + else: + return 0 + except (urllib.error.HTTPError, urllib.error.URLError) as error: + Domoticz.Log('La Freebox semble indisponible : '+ error.msg) + except timeout: + return 0 + + def setOnOFFWifi(self, p_isPutOn): + isOn = None + if p_isPutOn: + # data = {'ap_params': {'enabled': True}} + data = {'enabled': True} + else: + # data = {'ap_params': {'enabled': False}} + data = {'enabled': False} + try: + v_result = self.put( "wifi/config/",data) + isOn = False + if True == v_result['success']: + if v_result['result']['ap_params']['enabled']: + Domoticz.Log( "Wifi is now ON") + isOn = True + else: + Domoticz.Log("Wifi is now OFF") + except (urllib.error.HTTPError, urllib.error.URLError) as error: + Domoticz.Log('setOnOFFWifi Erreur '+ error.msg) + except timeout: + if not p_isPutOn: + # If we are connected using wifi, disabling wifi will close connection + # thus PUT response will never be received: a timeout is expected + Domoticz.Log("Wifi désactivé") + return False + else: + # Forward timeout exception as should not occur + raise timeout + # Response received + # ensure status_code is 200, else raise exception + # if requests.codes.ok != r.status_code: + # raise FbxOSException("Put error: %s" % r.text) + # rc is 200 but did we really succeed? + + # else: + # raise FbxOSException("Challenge failure: %s" % resp) + # self._logout() + return isOn + + def reboot(self): + v_result = self.com( "system/reboot") + if not v_result['success']: + Domoticz.Log("Erreur lors du Reboot") + Domoticz.Log("Freebox Server en cours de reboot.") \ No newline at end of file diff --git a/plugin.py b/plugin.py index d5757c6..4704feb 100644 --- a/plugin.py +++ b/plugin.py @@ -1,9 +1,10 @@ # Freebox Python Plugin # # Author: https://matdomotique.wordpress.com/ +# https://matdomotique.wordpress.com/2018/03/25/plugin-freebox-pour-domoticz/ # """ - + @@ -18,7 +19,7 @@ """ -import Domoticz,freebox,json,os,datetime +import Domoticz,freebox,json,os,datetime,time # from data import * #Pour le debug local sinon à mettre en commentaire from enum import Enum @@ -27,10 +28,8 @@ class FreeboxPlugin: deviceTypeDisk = 'DiskDevice' deviceSystemInfo = 'SystemInfoDevice' devicePresence = 'PresenceDevice' + deviceCommande = 'Commande' _fileNameDeviceMapping = 'devicemapping.json' - # _deviceTypeDisk = 'DiskDevice' - # _deviceSystemInfo = 'SystemInfoDevice' - # _devicePresence = 'PresenceDevice' enabled = False token = "" freeboxURL = "http://mafreebox.free.fr" @@ -148,17 +147,36 @@ class FreeboxPlugin: #Creation des device presence de la Freebox listeMacString = Parameters["Mode2"] - listeMac = listeMacString.split(";") - for macAdresse in listeMac: - name = f.getNameByMacAdresse(macAdresse) - if (name != None): - keyunit = self.getOrCreateUnitIdForDevice(self.DeviceType.devicePresence,macAdresse) - if (keyunit not in Devices): - v_dev = Domoticz.Device(Unit=keyunit, Name="Presence "+name, TypeName="Switch") - v_dev.Create() - Domoticz.Log("Création du dispositif "+"Presence "+name) - else: - Domoticz.Log("La mac adresse "+macAdresse+" est inconnu de la freebox, on ne crée aucun dispositif.") + if(listeMacString != ""): + listeMac = listeMacString.split(";") + for macAdresse in listeMac: + name = f.getNameByMacAdresse(macAdresse) + if (name != None): + keyunit = self.getOrCreateUnitIdForDevice(self.DeviceType.devicePresence,macAdresse) + if (keyunit not in Devices): + v_dev = Domoticz.Device(Unit=keyunit, Name="Presence "+name, TypeName="Switch") + v_dev.Create() + Domoticz.Log("Création du dispositif "+"Presence "+name) + else: + Domoticz.Log("La mac adresse "+macAdresse+" est inconnu de la freebox, on ne crée aucun dispositif.") + + #Creation du device d'activation/désactivation du WIFI + v_etatWIFI = f.isOnWIFI() + Domoticz.Log("Etat WIFI : "+ str(v_etatWIFI)) + keyunit = self.getOrCreateUnitIdForDevice(self.DeviceType.deviceCommande,"WIFI") + if (keyunit not in Devices): + v_dev = Domoticz.Device(Unit=keyunit, Name="WIFI On/Off", TypeName="Switch") + v_dev.Create() + Domoticz.Log("Création du dispositif "+"WIFI On/Off") + self.updateDeviceIfExist(self.DeviceType.deviceCommande,"WIFI",v_etatWIFI, str(v_etatWIFI)) + #Creation du device de reboot du Freebox server + #f.reboot() + keyunit = self.getOrCreateUnitIdForDevice(self.DeviceType.deviceCommande,"REBOOT") + if (keyunit not in Devices): + v_dev = Domoticz.Device(Unit=keyunit, Name="Reboot Server", TypeName="Switch") + v_dev.Create() + Domoticz.Log("Création du dispositif "+"Reboot Server") + DumpConfigToLog() def onStop(self): @@ -172,6 +190,28 @@ class FreeboxPlugin: def onCommand(self, Unit, Command, Level, Hue): Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level)) + # 2018-04-02 20:26:01.192 User: Admin initiated a switch command (17/Freebox - Presence iPhonedMatthieu/On) + # 2018-04-02 20:26:01.209 (Freebox) onCommand called for Unit 5: Parameter 'On', Level: 0 + # 2018-04-02 20:27:50.550 User: Admin initiated a switch command (17/Freebox - Presence iPhonedMatthieu/Off) + # 2018-04-02 20:27:50.552 (Freebox) onCommand called for Unit 5: Parameter 'Off', Level: 0 + # 2018-04-02 20:28:44.350 User: Admin initiated a switch command (18/Freebox - Presence iPhonedTiphaine/On) + # 2018-04-02 20:28:44.380 (Freebox) onCommand called for Unit 6: Parameter 'On', Level: 0 + keyunit = self.getOrCreateUnitIdForDevice(self.DeviceType.deviceCommande,"WIFI") + if (keyunit == Unit): + f=freebox.FbxApp("idPluginDomoticz",self.token,host=self.freeboxURL) + if(str(Command) == "On"): + f.setOnOFFWifi(1) + else: + f.setOnOFFWifi(0) + time.sleep(1) + #On remet à jour l'état du wifi suite à la modification + v_etatWIFI = f.isOnWIFI() + self.updateDeviceIfExist(self.DeviceType.deviceCommande,"WIFI",v_etatWIFI, str(v_etatWIFI)) + + keyunit = self.getOrCreateUnitIdForDevice(self.DeviceType.deviceCommande,"REBOOT") + if (keyunit == Unit): + f=freebox.FbxApp("idPluginDomoticz",self.token,host=self.freeboxURL) + f.reboot() def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile): Domoticz.Log("Notification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile) @@ -211,11 +251,18 @@ class FreeboxPlugin: for periph in lanPeriph: Domoticz.Debug(lanPeriph[periph]+" ("+periph+") présent") + v_etatWIFI = f.isOnWIFI() + self.updateDeviceIfExist(self.DeviceType.deviceCommande,"WIFI",v_etatWIFI, str(v_etatWIFI)) + global _plugin _plugin = FreeboxPlugin() def onStart(): global _plugin + # on fait une pause de 10 secondes au démarrage pour attendre la Freebox si besoin + # correction apporté par Gells qui avait des erreur au démarrage + #https://easydomoticz.com/forum/viewtopic.php?f=10&t=6222&p=55468#p55442 + time.sleep(5) _plugin.onStart() def onStop():