<filename>convenience/smart_home/Welcome.py
"""
coding=utf-8
"""
import imghdr, time

from . import NoDevice, postRequest, _BASE_URL

_GETHOMEDATA_REQ = _BASE_URL + "api/gethomedata"
_GETCAMERAPICTURE_REQ = _BASE_URL + "api/getcamerapicture"
_GETEVENTSUNTIL_REQ = _BASE_URL + "api/geteventsuntil"

class WelcomeData:
    """
    List the Netatmo Welcome cameras informations (Homes, cameras, events, persons)

    Args:
        authData (ClientAuth): Authentication information with a working access Token
    """
    def __init__(self, authData, size=15):
        self.getAuthToken = authData.accessToken
        postParams = {
            "access_token" : self.getAuthToken,
            "size" : size
            }
        resp = postRequest(_GETHOMEDATA_REQ, postParams)
        self.rawData = resp['body']
        self.homes = { d['id'] : d for d in self.rawData['homes'] }
        if not self.homes : raise NoDevice("No camera available")
        self.persons = dict()
        self.events = dict()
        self.cameras = dict()
        self.modules = dict()
        self.lastEvent = dict()
        for i in range(len(self.rawData['homes'])):
            nameHome=self.rawData['homes'][i]['name']
            if nameHome not in self.cameras:
                self.cameras[nameHome]=dict()
            for p in self.rawData['homes'][i]['persons']:
                self.persons[ p['id'] ] = p
            for e in self.rawData['homes'][i]['events']:
                if e['camera_id'] not in self.events:
                    self.events[ e['camera_id'] ] = dict()
                self.events[ e['camera_id'] ][ e['time'] ] = e
            for c in self.rawData['homes'][i]['cameras']:
                self.cameras[nameHome][ c['id'] ] = c
                for m in c['modules']:
                    self.modules[ m['id'] ] = m
                    self.modules[ m['id'] ][ 'cam_id' ] = c['id']
        for camera in self.events:
            self.lastEvent[camera]=self.events[camera][sorted(self.events[camera])[-1]]
        self.default_home = list(self.homes.values())[0]['name']
        self.default_module = list(self.modules.values())[0]['name']
        self.default_camera = list(self.cameras[self.default_home].values())[0]

    def homeById(self, hid):
        return None if hid not in self.homes else self.homes[hid]

    def homeByName(self, home=None):
        if not home: return self.homeByName(self.default_home)
        for key,value in self.homes.items():
            if value['name'] == home:
                return self.homes[key]

    def cameraById(self, cid):
        for home,cam in self.cameras.items():
            if cid in self.cameras[home]:
                return self.cameras[home][cid]
        return None

    def cameraByName(self, camera=None, home=None):
        if not camera and not home:
            return self.default_camera
        elif home and camera:
            if home not in self.cameras:
                return None
            for cam_id in self.cameras[home]:
                if self.cameras[home][cam_id]['name'] == camera:
                    return self.cameras[home][cam_id]
        elif not home and camera:
            for home, cam_ids in self.cameras.items():
                for cam_id in cam_ids:
                    if self.cameras[home][cam_id]['name'] == camera:
                        return self.cameras[home][cam_id]
        else:
            return list(self.cameras[home].values())[0]
        return None

    def moduleById(self, mid):
        return None if mid not in self.modules else self.modules[mid]

    def moduleByName(self, module=None, camera=None, home=None):
        if not module:
            return self.moduleByName(self.default_module)
        cam = None
        if camera or home:
            cam = self.cameraByName(camera, home)
            if not cam:
                return None
        for key,value in self.modules.items():
            if value['name'] == module:
                if cam and value['cam_id'] != cam['id']:
                    return None
                return self.modules[key]
        return None

    def cameraUrls(self, camera=None, home=None, cid=None):
        """
        Return the vpn_url and the local_url (if available) of a given camera
        in order to access to its live feed
        """
        local_url = None
        vpn_url = None
        if cid:
            camera_data=self.cameraById(cid)
        else:
            camera_data=self.cameraByName(camera=camera, home=home)
        if camera_data:
            vpn_url = camera_data['vpn_url']
            if camera_data['is_local']:
                resp = postRequest('{0}/command/ping'.format(camera_data['vpn_url']),dict())
                temp_local_url=resp['local_url']
                resp = postRequest('{0}/command/ping'.format(temp_local_url),dict())
                if temp_local_url == resp['local_url']:
                    local_url = temp_local_url
        return vpn_url, local_url

    def personsAtHome(self, home=None):
        """
        Return the list of known persons who are currently at home
        """
        if not home: home = self.default_home
        home_data = self.homeByName(home)
        atHome = []
        for p in home_data['persons']:
            #Only check known persons
            if 'pseudo' in p:
                if not p["out_of_sight"]:
                    atHome.append(p['pseudo'])
        return atHome

    def getCameraPicture(self, image_id, key):
        """
        Download a specific image (of an event or user face) from the camera
        """
        postParams = {
            "access_token" : self.getAuthToken,
            "image_id" : image_id,
            "key" : key
            }
        resp = postRequest(_GETCAMERAPICTURE_REQ, postParams, json_resp=False, body_size=None)
        image_type = imghdr.what('NONE.FILE',resp)
        return resp, image_type

    def getProfileImage(self, name):
        """
        Retrieve the face of a given person
        """
        for p in self.persons:
            if 'pseudo' in self.persons[p]:
                if name == self.persons[p]['pseudo']:
                    image_id = self.persons[p]['face']['id']
                    key = self.persons[p]['face']['key']
                    return self.getCameraPicture(image_id, key)
        return None, None

    def updateEvent(self, event=None, home=None):
        """
        Update the list of event with the latest ones
        """
        if not home: home=self.default_home
        if not event:
            #If not event is provided we need to retrieve the oldest of the last event seen by each camera
            listEvent = dict()
            for cam_id in self.lastEvent:
                listEvent[self.lastEvent[cam_id]['time']] = self.lastEvent[cam_id]
            event = listEvent[sorted(listEvent)[0]]

        home_data = self.homeByName(home)
        postParams = {
            "access_token" : <PASSWORD>,
            "home_id" : home_data['id'],
            "event_id" : event['id']
        }
        resp = postRequest(_GETEVENTSUNTIL_REQ, postParams)
        eventList = resp['body']['events_list']
        for e in eventList:
            self.events[ e['camera_id'] ][ e['time'] ] = e
        for camera in self.events:
            self.lastEvent[camera]=self.events[camera][sorted(self.events[camera])[-1]]

    def personSeenByCamera(self, name, home=None, camera=None):
        """
        Return True if a specific person has been seen by a camera
        """
        try:
            cam_id = self.cameraByName(camera=camera, home=home)['id']
        except TypeError:
            print("personSeenByCamera: Camera name or home is unknown")
            return False
        #Check in the last event is someone known has been seen
        if self.lastEvent[cam_id]['type'] == 'person':
            person_id = self.lastEvent[cam_id]['person_id']
            if 'pseudo' in self.persons[person_id]:
                if self.persons[person_id]['pseudo'] == name:
                    return True
        return False

    def _knownPersons(self):
        known_persons = dict()
        for p_id,p in self.persons.items():
            if 'pseudo' in p:
                known_persons[ p_id ] = p
        return known_persons

    def someoneKnownSeen(self, home=None, camera=None, exclude=0):
        """
        Return True if someone known has been seen
        """
        try:
            cam_id = self.cameraByName(camera=camera, home=home)['id']
        except TypeError:
            print("someoneKnownSeen: Camera name or home is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif self.events[cam_id][time_ev]['type'] == 'person':
                    if self.events[cam_id][time_ev]['person_id'] in self._knownPersons():
                        return True
        #Check in the last event is someone known has been seen
        elif self.lastEvent[cam_id]['type'] == 'person':
            if self.lastEvent[cam_id]['person_id'] in self._knownPersons():
                return True
        return False

    def someoneUnknownSeen(self, home=None, camera=None, exclude=0):
        """
        Return True if someone unknown has been seen
        """
        try:
            cam_id = self.cameraByName(camera=camera, home=home)['id']
        except TypeError:
            print("someoneUnknownSeen: Camera name or home is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif self.events[cam_id][time_ev]['type'] == 'person':
                    if self.events[cam_id][time_ev]['person_id'] not in self._knownPersons():
                        return True
        #Check in the last event is someone known has been seen
        elif self.lastEvent[cam_id]['type'] == 'person':
            if self.lastEvent[cam_id]['person_id'] not in self._knownPersons():
                return True
        return False

    def motionDetected(self, home=None, camera=None, exclude=0):
        """
        Return True if movement has been detected
        """
        try:
            cam_id = self.cameraByName(camera=camera, home=home)['id']
        except TypeError:
            print("motionDetected: Camera name or home is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif self.events[cam_id][time_ev]['type'] == 'movement':
                    return True
        elif self.lastEvent[cam_id]['type'] == 'movement':
            return True
        return False

    def moduleMotionDetected(self, module=None, home=None, camera=None, exclude=0):
        """
        Return True if movement has been detected
        """
        try:
            mod = self.moduleByName(module, camera=camera, home=home)
            mod_id = mod['id']
            cam_id = mod['cam_id']
        except TypeError:
            print("moduleMotionDetected: Module name or Camera name or home is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif (self.events[cam_id][time_ev]['type'] == 'tag_big_move' or\
                      self.events[cam_id][time_ev]['type'] == 'tag_small_move') and\
                      self.events[cam_id][time_ev]['module_id'] == mod_id:
                    return True
        elif (self.lastEvent[cam_id]['type'] == 'tag_big_move' or\
              self.lastEvent[cam_id]['type'] == 'tag_small_move') and\
              self.lastEvent[cam_id]['type']['module_id'] == mod_id:
            return True
        return False

    def moduleOpened(self, module=None, home=None, camera=None):
        """
        Return True if module status is open
        """
        try:
            mod = self.moduleByName(module, camera=camera, home=home)
            mod_id = mod['id']
            cam_id = mod['cam_id']
        except TypeError:
            print("moduleOpened: Camera name, or home, or module is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif self.events[cam_id][time_ev]['type'] == 'tag_open' and\
                     self.events[cam_id][time_ev]['module_id'] == mod_id:
                    return True
        elif self.lastEvent[cam_id]['type'] == 'tag_open' and\
             self.lastEvent[cam_id]['type']['module_id'] == mod_id:
            return True
        return False


<filename>convenience/smart_home/Welcome.py
"""
coding=utf-8
"""
import imghdr, time

from . import NoDevice, postRequest, _BASE_URL

_GETHOMEDATA_REQ = _BASE_URL + "api/gethomedata"
_GETCAMERAPICTURE_REQ = _BASE_URL + "api/getcamerapicture"
_GETEVENTSUNTIL_REQ = _BASE_URL + "api/geteventsuntil"

class WelcomeData:
    """
    List the Netatmo Welcome cameras informations (Homes, cameras, events, persons)

    Args:
        authData (ClientAuth): Authentication information with a working access Token
    """
    def __init__(self, authData, size=15):
        self.getAuthToken = authData.accessToken
        postParams = {
            "access_token" : self.getAuthToken,
            "size" : size
            }
        resp = postRequest(_GETHOMEDATA_REQ, postParams)
        self.rawData = resp['body']
        self.homes = { d['id'] : d for d in self.rawData['homes'] }
        if not self.homes : raise NoDevice("No camera available")
        self.persons = dict()
        self.events = dict()
        self.cameras = dict()
        self.modules = dict()
        self.lastEvent = dict()
        for i in range(len(self.rawData['homes'])):
            nameHome=self.rawData['homes'][i]['name']
            if nameHome not in self.cameras:
                self.cameras[nameHome]=dict()
            for p in self.rawData['homes'][i]['persons']:
                self.persons[ p['id'] ] = p
            for e in self.rawData['homes'][i]['events']:
                if e['camera_id'] not in self.events:
                    self.events[ e['camera_id'] ] = dict()
                self.events[ e['camera_id'] ][ e['time'] ] = e
            for c in self.rawData['homes'][i]['cameras']:
                self.cameras[nameHome][ c['id'] ] = c
                for m in c['modules']:
                    self.modules[ m['id'] ] = m
                    self.modules[ m['id'] ][ 'cam_id' ] = c['id']
        for camera in self.events:
            self.lastEvent[camera]=self.events[camera][sorted(self.events[camera])[-1]]
        self.default_home = list(self.homes.values())[0]['name']
        self.default_module = list(self.modules.values())[0]['name']
        self.default_camera = list(self.cameras[self.default_home].values())[0]

    def homeById(self, hid):
        return None if hid not in self.homes else self.homes[hid]

    def homeByName(self, home=None):
        if not home: return self.homeByName(self.default_home)
        for key,value in self.homes.items():
            if value['name'] == home:
                return self.homes[key]

    def cameraById(self, cid):
        for home,cam in self.cameras.items():
            if cid in self.cameras[home]:
                return self.cameras[home][cid]
        return None

    def cameraByName(self, camera=None, home=None):
        if not camera and not home:
            return self.default_camera
        elif home and camera:
            if home not in self.cameras:
                return None
            for cam_id in self.cameras[home]:
                if self.cameras[home][cam_id]['name'] == camera:
                    return self.cameras[home][cam_id]
        elif not home and camera:
            for home, cam_ids in self.cameras.items():
                for cam_id in cam_ids:
                    if self.cameras[home][cam_id]['name'] == camera:
                        return self.cameras[home][cam_id]
        else:
            return list(self.cameras[home].values())[0]
        return None

    def moduleById(self, mid):
        return None if mid not in self.modules else self.modules[mid]

    def moduleByName(self, module=None, camera=None, home=None):
        if not module:
            return self.moduleByName(self.default_module)
        cam = None
        if camera or home:
            cam = self.cameraByName(camera, home)
            if not cam:
                return None
        for key,value in self.modules.items():
            if value['name'] == module:
                if cam and value['cam_id'] != cam['id']:
                    return None
                return self.modules[key]
        return None

    def cameraUrls(self, camera=None, home=None, cid=None):
        """
        Return the vpn_url and the local_url (if available) of a given camera
        in order to access to its live feed
        """
        local_url = None
        vpn_url = None
        if cid:
            camera_data=self.cameraById(cid)
        else:
            camera_data=self.cameraByName(camera=camera, home=home)
        if camera_data:
            vpn_url = camera_data['vpn_url']
            if camera_data['is_local']:
                resp = postRequest('{0}/command/ping'.format(camera_data['vpn_url']),dict())
                temp_local_url=resp['local_url']
                resp = postRequest('{0}/command/ping'.format(temp_local_url),dict())
                if temp_local_url == resp['local_url']:
                    local_url = temp_local_url
        return vpn_url, local_url

    def personsAtHome(self, home=None):
        """
        Return the list of known persons who are currently at home
        """
        if not home: home = self.default_home
        home_data = self.homeByName(home)
        atHome = []
        for p in home_data['persons']:
            #Only check known persons
            if 'pseudo' in p:
                if not p["out_of_sight"]:
                    atHome.append(p['pseudo'])
        return atHome

    def getCameraPicture(self, image_id, key):
        """
        Download a specific image (of an event or user face) from the camera
        """
        postParams = {
            "access_token" : self.getAuthToken,
            "image_id" : image_id,
            "key" : key
            }
        resp = postRequest(_GETCAMERAPICTURE_REQ, postParams, json_resp=False, body_size=None)
        image_type = imghdr.what('NONE.FILE',resp)
        return resp, image_type

    def getProfileImage(self, name):
        """
        Retrieve the face of a given person
        """
        for p in self.persons:
            if 'pseudo' in self.persons[p]:
                if name == self.persons[p]['pseudo']:
                    image_id = self.persons[p]['face']['id']
                    key = self.persons[p]['face']['key']
                    return self.getCameraPicture(image_id, key)
        return None, None

    def updateEvent(self, event=None, home=None):
        """
        Update the list of event with the latest ones
        """
        if not home: home=self.default_home
        if not event:
            #If not event is provided we need to retrieve the oldest of the last event seen by each camera
            listEvent = dict()
            for cam_id in self.lastEvent:
                listEvent[self.lastEvent[cam_id]['time']] = self.lastEvent[cam_id]
            event = listEvent[sorted(listEvent)[0]]

        home_data = self.homeByName(home)
        postParams = {
            "access_token" : <PASSWORD>,
            "home_id" : home_data['id'],
            "event_id" : event['id']
        }
        resp = postRequest(_GETEVENTSUNTIL_REQ, postParams)
        eventList = resp['body']['events_list']
        for e in eventList:
            self.events[ e['camera_id'] ][ e['time'] ] = e
        for camera in self.events:
            self.lastEvent[camera]=self.events[camera][sorted(self.events[camera])[-1]]

    def personSeenByCamera(self, name, home=None, camera=None):
        """
        Return True if a specific person has been seen by a camera
        """
        try:
            cam_id = self.cameraByName(camera=camera, home=home)['id']
        except TypeError:
            print("personSeenByCamera: Camera name or home is unknown")
            return False
        #Check in the last event is someone known has been seen
        if self.lastEvent[cam_id]['type'] == 'person':
            person_id = self.lastEvent[cam_id]['person_id']
            if 'pseudo' in self.persons[person_id]:
                if self.persons[person_id]['pseudo'] == name:
                    return True
        return False

    def _knownPersons(self):
        known_persons = dict()
        for p_id,p in self.persons.items():
            if 'pseudo' in p:
                known_persons[ p_id ] = p
        return known_persons

    def someoneKnownSeen(self, home=None, camera=None, exclude=0):
        """
        Return True if someone known has been seen
        """
        try:
            cam_id = self.cameraByName(camera=camera, home=home)['id']
        except TypeError:
            print("someoneKnownSeen: Camera name or home is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif self.events[cam_id][time_ev]['type'] == 'person':
                    if self.events[cam_id][time_ev]['person_id'] in self._knownPersons():
                        return True
        #Check in the last event is someone known has been seen
        elif self.lastEvent[cam_id]['type'] == 'person':
            if self.lastEvent[cam_id]['person_id'] in self._knownPersons():
                return True
        return False

    def someoneUnknownSeen(self, home=None, camera=None, exclude=0):
        """
        Return True if someone unknown has been seen
        """
        try:
            cam_id = self.cameraByName(camera=camera, home=home)['id']
        except TypeError:
            print("someoneUnknownSeen: Camera name or home is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif self.events[cam_id][time_ev]['type'] == 'person':
                    if self.events[cam_id][time_ev]['person_id'] not in self._knownPersons():
                        return True
        #Check in the last event is someone known has been seen
        elif self.lastEvent[cam_id]['type'] == 'person':
            if self.lastEvent[cam_id]['person_id'] not in self._knownPersons():
                return True
        return False

    def motionDetected(self, home=None, camera=None, exclude=0):
        """
        Return True if movement has been detected
        """
        try:
            cam_id = self.cameraByName(camera=camera, home=home)['id']
        except TypeError:
            print("motionDetected: Camera name or home is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif self.events[cam_id][time_ev]['type'] == 'movement':
                    return True
        elif self.lastEvent[cam_id]['type'] == 'movement':
            return True
        return False

    def moduleMotionDetected(self, module=None, home=None, camera=None, exclude=0):
        """
        Return True if movement has been detected
        """
        try:
            mod = self.moduleByName(module, camera=camera, home=home)
            mod_id = mod['id']
            cam_id = mod['cam_id']
        except TypeError:
            print("moduleMotionDetected: Module name or Camera name or home is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif (self.events[cam_id][time_ev]['type'] == 'tag_big_move' or\
                      self.events[cam_id][time_ev]['type'] == 'tag_small_move') and\
                      self.events[cam_id][time_ev]['module_id'] == mod_id:
                    return True
        elif (self.lastEvent[cam_id]['type'] == 'tag_big_move' or\
              self.lastEvent[cam_id]['type'] == 'tag_small_move') and\
              self.lastEvent[cam_id]['type']['module_id'] == mod_id:
            return True
        return False

    def moduleOpened(self, module=None, home=None, camera=None):
        """
        Return True if module status is open
        """
        try:
            mod = self.moduleByName(module, camera=camera, home=home)
            mod_id = mod['id']
            cam_id = mod['cam_id']
        except TypeError:
            print("moduleOpened: Camera name, or home, or module is unknown")
            return False

        if exclude:
            limit = (time.time() - exclude)
            array_time_event = sorted(self.events[cam_id])
            array_time_event.reverse()
            for time_ev in array_time_event:
                if time_ev < limit:
                    return False
                elif self.events[cam_id][time_ev]['type'] == 'tag_open' and\
                     self.events[cam_id][time_ev]['module_id'] == mod_id:
                    return True
        elif self.lastEvent[cam_id]['type'] == 'tag_open' and\
             self.lastEvent[cam_id]['type']['module_id'] == mod_id:
            return True
        return False


coding=utf-8 List the Netatmo Welcome cameras informations (Homes, cameras, events, persons)      Args:         authData (ClientAuth): Authentication information with a working access Token Return the vpn_url and the local_url (if available) of a given camera         in order to access to its live feed Return the list of known persons who are currently at home #Only check known persons Download a specific image (of an event or user face) from the camera Retrieve the face of a given person Update the list of event with the latest ones #If not event is provided we need to retrieve the oldest of the last event seen by each camera Return True if a specific person has been seen by a camera #Check in the last event is someone known has been seen Return True if someone known has been seen #Check in the last event is someone known has been seen Return True if someone unknown has been seen #Check in the last event is someone known has been seen Return True if movement has been detected Return True if movement has been detected Return True if module status is open