예제 #1
0
def ConnectAndSetOnOff(email, password, name=None, uuid=None, mac=None, action='on'):
    """ Connect to Meross Cloud and set on or off a smartplug """

    if mac and not name and not uuid: Exit("<F> Error : not implemented !")
    if not name and not uuid and not mac:
        Exit("<F> Error : need at least 'name', 'uuid' or 'mac' parameter to set on or off a smartplug !")

    try:
        httpHandler = MerossHttpClient(email, password)
    except:
        Exit("<F> Error : can't connect to Meross Cloud ! Please verify Internet connection, email and password !")

    # Retrieves the list of supported devices
    devices = httpHandler.list_supported_devices()

    device = None
    for d in devices:
       if (d._uuid == uuid) or (d._name == name):
           device = d
           break

    try:
       if action == 'on':
            device.turn_on()
       else:
            device.turn_off()
    except:
        pass

    return        
예제 #2
0
  def scan_power_switches(callback=None, **kwargs):
    if '' == kwargs['meross_username'] or '' == kwargs['meross_password']:
      logger.info('Meross cloud is not enabled.')
      return

    try:
      httpHandler = MerossHttpClient(email=kwargs['meross_username'], password=kwargs['meross_password'])
      logger.info('Logged into Meross cloud successfull.')

      devices = httpHandler.list_supported_devices()
      if len(devices) == 0:
        logger.warning('Unfortunaly your Meross device is not supported by this software. We found zero power switches.')
      for counter, device in enumerate(devices):
        data = device.get_sys_data()

        try:
          for channel_data in data['all']['digest']['togglex']:
            if int(channel_data['channel']) > 0:
              yield terrariumPowerSwitch(md5((terrariumPowerSwitchMSS425E.TYPE + data['all']['system']['hardware']['macAddress'] + str(channel_data['channel'])).encode()).hexdigest(),
                                         terrariumPowerSwitchMSS425E.TYPE,
                                         (device,int(channel_data['channel'])),
                                         'Channel {}'.format(channel_data['channel']),
                                         None,
                                         callback)

        except Exception as ex:
          print('Scan error in terrariumPowerSwitchMSS425E')
          print(ex)

    except UnauthorizedException as ex:
      logger.error('Authentication error with Merros cloud for \'{}\' type power switch. Please check username and password.'.format(terrariumPowerSwitchMSS425E.TYPE))
예제 #3
0
    def setUp(self):
        httpHandler = MerossHttpClient(email=EMAIL, password=PASSWORD)

        # Retrieves the list of supported devices
        devices = httpHandler.list_supported_devices()
        for counter, device in enumerate(devices):
            if isinstance(device, Mss310):
                self.device = device
                break
예제 #4
0
class TestHttpMethods(unittest.TestCase):
    def setUp(self):
        self.client = MerossHttpClient(email=EMAIL, password=PASSWORD)

    def test_device_listing(self):
        devices = self.client.list_devices()
        assert devices is not None
        assert len(devices) > 0

    def test_supported_device_listing(self):
        devices = self.client.list_devices()
        assert devices is not None
        assert len(devices) > 0
예제 #5
0
    def __init__(self, meross_email, meross_password):
        self._devices_lock = RLock()
        self._devices = dict()
        self._event_callbacks_lock = RLock()
        self._event_callbacks = []

        self._http_client = MerossHttpClient(email=meross_email, password=meross_password)
        self._cloud_creds = self._http_client.get_cloud_credentials()

        # Instantiate the mqtt cloud client
        self._cloud_client = MerossCloudClient(cloud_credentials=self._cloud_creds,
                                               push_message_callback=self._dispatch_push_notification)
        self._cloud_client.connection_status.register_connection_event_callback(callback=self._fire_event)
예제 #6
0
    def login(self):

        global device1

        user = self.e1.get()
        passw = self.e2.get()

        httphandler = MerossHttpClient(email=user, password=passw)
        devices = httphandler.list_supported_devices()

        for counter, device in enumerate(devices):
            device1 = device

        self.master.switch_frame(GraphPage)
예제 #7
0
    def __init__(self, cloud_credentials, discovery_interval, auto_reconnect):
        self._cloud_creds = cloud_credentials
        self._http_client = MerossHttpClient(cloud_credentials=self._cloud_creds)

        self._devices_lock = lock_factory.build_rlock()
        self._devices = dict()
        self._event_callbacks_lock = lock_factory.build_rlock()
        self._event_callbacks = []

        # Instantiate the mqtt cloud client
        self._cloud_client = MerossCloudClient(cloud_credentials=self._cloud_creds,
                                               push_message_callback=self._dispatch_push_notification,
                                               auto_reconnect=auto_reconnect)
        self._cloud_client.connection_status.register_connection_event_callback(callback=self._fire_event)
        self._device_discoverer = None
        self._stop_discovery = Event()
        self._device_discovery_done = Event()
        self._discovery_interval = discovery_interval
예제 #8
0
 def from_email_and_password(cls,
                             meross_email,
                             meross_password,
                             discovery_interval=30.0,
                             auto_reconnect=True
                             ):
     cloud_creds = MerossHttpClient.login(email=meross_email, password=meross_password)
     return MerossManager(
         cloud_credentials=cloud_creds,
         discovery_interval=discovery_interval,
         auto_reconnect=auto_reconnect)
예제 #9
0
def ConnectAndRefreshAll(email, password):
    """ Connect to Meross Cloud and refresh all devices and informations """

    try:
        httpHandler = MerossHttpClient(email, password)
    except:
        Exit(
            "<F> Error : can't connect to Meross Cloud ! Please verify Internet connection, email and password !"
        )

    # Retrieves the list of supported devices
    devices = httpHandler.list_supported_devices()

    # Build dict of devices informations
    d_devices = {}

    for num in range(len(devices)):
        if debug:
            print(50 * '=' + '\nnum=', num)
        device = devices[num]

        d = RefreshOneDevice(device=device)

        uuid = device._uuid
        d_devices[uuid] = d

    if debug:
        pprint.pprint(d_devices)

    # Save dictionnary into Pickle file
    # f = open(pklfile,"wb")
    # pickle.dump(d_devices,f)
    # f.close()

    # Save dictionnary into JSON file
    # l_devices = list(d_devices.values())
    # print(l_devices)
    # with open(jsonfile, 'w') as fp:
    #   json.dump(d_devices, fp)

    return d_devices
예제 #10
0
def setup(hass, config):
    """Set up Tuya Component."""
    from meross_iot.api import MerossHttpClient

    username = config[DOMAIN][CONF_USERNAME]
    password = config[DOMAIN][CONF_PASSWORD]

    meross = MerossHttpClient(email=username, password=password)
    hass.data[DATA_MEROSS] = meross
    hass.data[DOMAIN] = {'entities': {}}

    def load_devices():
        hass.data[DATA_DEVICES] = {}
        for device in meross.list_supported_devices():
            hass.data[DATA_DEVICES][device.device_id()] = device
        """Load new devices by device_list."""
        device_type_list = {}
        for device in hass.data[DATA_DEVICES].values():
            if device.device_id() not in hass.data[DOMAIN]['entities']:
                ha_type = 'switch'
                if ha_type not in device_type_list:
                    device_type_list[ha_type] = []
                device_type_list[ha_type].append(device.device_id())
                hass.data[DOMAIN]['entities'][device.device_id()] = None
        for ha_type, dev_ids in device_type_list.items():
            discovery.load_platform(hass, ha_type, DOMAIN,
                                    {'dev_ids': dev_ids}, config)

    load_devices()

    def poll_devices_update(event_time):
        """Check if accesstoken is expired and pull device list from server."""
        _LOGGER.debug("Pull devices from Meross.")
        # Add new discover device.
        load_devices()
        # Delete not exist device.
        for dev_id in list(hass.data[DOMAIN]['entities']):
            if dev_id not in hass.data[DATA_DEVICES].keys():
                dispatcher_send(hass, SIGNAL_DELETE_ENTITY, dev_id)
                hass.data[DOMAIN]['entities'].pop(dev_id)

    track_time_interval(hass, poll_devices_update, timedelta(minutes=15))

    hass.services.register(DOMAIN, SERVICE_PULL_DEVICES, poll_devices_update)

    def force_update(call):
        """Force all devices to pull data."""
        dispatcher_send(hass, SIGNAL_UPDATE_ENTITY)

    hass.services.register(DOMAIN, SERVICE_FORCE_UPDATE, force_update)

    return True
예제 #11
0
def countdown_task(meross_device, meross_channel, meross_email,
                   meross_password, seconds):
    print("Turn off the device for %s seconds" % seconds)

    http_handler = MerossHttpClient(email=meross_email,
                                    password=meross_password)

    # get my device by name
    device = get_device(http_handler, meross_device)
    if device is not None:
        channels = device.get_channels()
        if channels[0] is not None:
            device.turn_off_channel(channels[int(meross_channel)])
            time.sleep(int(seconds))
            print("Turn back on the device")
            device.turn_on_channel(channels[int(meross_channel)])
예제 #12
0
def get_or_renew_creds(email, password, stored_creds):
    try:
        if stored_creds is None:
            http_client = MerossHttpClient.from_user_password(email=email, password=password)
        else:
            http_client = MerossHttpClient(cloud_credentials=stored_creds)

        # Test device listing. If goes ok, return it immediately
        http_devices = http_client.list_devices()
        return http_client.get_cloud_credentials(), http_devices

    except TokenException:
        # In case the current token is expired or invalid, let's try to re-login.
        _LOGGER.warning("Current token has been refused by the Meross Cloud. Trying to generate a new one with "
                        "stored user credentials...")

        # Build a new client with username/password rather than using stored credentials
        http_client = MerossHttpClient.from_user_password(email=email, password=password)
        http_devices = http_client.list_devices()
        return http_client.get_cloud_credentials(), http_devices
예제 #13
0
def ConnectAndRefreshAll(email, password):
    """ Connect to Meross Cloud and refresh all devices and informations """

    try:
        httpHandler = MerossHttpClient(email, password)
    except:
        Exit("<F> Error : can't connect to Meross Cloud ! Please verify Internet connection, email and password !")

    # Retrieves the list of supported devices
    devices = httpHandler.list_supported_devices()

    #print(devices)
    #print(50*'=')

    # Build dict of devices informations
    d_devices = {}

    for num in range(len(devices)):
        if debug: print(50*'=' + '\nnum=', num)
        device = devices[num]
        #if not device._name == 'Meross multi 1':
        #pprint.pprint(device)
        #print (device._name)
        data = device.get_sys_data()
        if debug: pprint.pprint(data)
        #pprint.pprint(device)
        uuid = device._uuid

        d_devices[uuid] = dict( {
            'name':     device._name,
            'ip':       data['all']['system']['firmware']['innerIp'],
            'mac':      data['all']['system']['hardware']['macAddress'],
            'online':   data['all']['system']['online']['status'],
            'uuid':     uuid,
            'type':     data['all']['system']['hardware']['type'],
            'firmversion':  data['all']['system']['firmware']['version'],
            'hardversion':  data['all']['system']['hardware']['version']
            } )

        # on/off status
        onoff = []
        try:
            onoff = [ data['all']['control']['toggle']['onoff'] ]
        except:
            try:
                ll = data['all']['digest']['togglex']
                onoff = [ x['onoff'] for x in ll ]
            except:
                pass
        d_devices[uuid]['onoff'] = onoff

        # Current power
        try:
            electricity = device.get_electricity()
            d_devices[uuid]['power'] = electricity['electricity']['power']
        except:
            d_devices[uuid]['power'] = '-1'

        # Historical consumption
        try:
            l_consumption = device.get_power_consumptionX()['consumptionx']
        except:
            l_consumption = []

        d_devices[uuid]['consumption'] = []   # on decide de ne pas la stocker

        # Yesterday consumption
        today = datetime.today()
        yesterday = (today - timedelta(1) ).strftime("%Y-%m-%d")
        d_devices[uuid]['consumption_yesterday'] = -1

        for c in l_consumption:
            if c['date'] == yesterday:
                try:
                    d_devices[uuid]['consumption_yesterday'] = c['value']
                except:
                    d_devices[uuid]['consumption_yesterday'] = -1
                break

    if debug: pprint.pprint(d_devices)

    # Save dictionnary into Pickle file
    f = open(pklfile,"wb")
    pickle.dump(d_devices,f)
    f.close()

    # Save dictionnary into JSON file
    l_devices = list(d_devices.values())
    #print(l_devices)
    with open(jsonfile, 'w') as fp:
        json.dump(d_devices, fp)
    return d_devices
예제 #14
0
 def _test_authorization(username, password):
     client = MerossHttpClient(email=username, password=password)
     client.get_cloud_credentials()
예제 #15
0
def ConnectAndSetOnOff(devices,
                       email,
                       password,
                       name=None,
                       uuid=None,
                       mac=None,
                       action='on',
                       channel='0'):
    """ Connect to Meross Cloud and set on or off a smartplug """

    if mac and not name and not uuid:
        Exit("<F> Error : not implemented !")
    if not name and not uuid and not mac:
        Exit(
            "<F> Error : need at least 'name', 'uuid' or 'mac' parameter to set on or off a smartplug !"
        )

    try:
        httpHandler = MerossHttpClient(email, password)
    except:
        Exit(
            "<F> Error : can't connect to Meross Cloud ! Please verify Internet connection, email and password !"
        )

    # Retrieves the list of supported devices
    ldevices = httpHandler.list_supported_devices()

    device = None
    for d in ldevices:
        if (d._uuid == uuid) or (d._name == name):
            device = d
            break

    uuid = d._uuid
    #pprint.pprint( devices[uuid] )
    if len(devices[uuid]['onoff']) == 1:
        try:
            if action == 'on':
                device.turn_on()
            else:
                device.turn_off()
        except:
            pass
    else:
        try:
            if action == 'on':
                if channel == '0':
                    device.turn_on()
                else:
                    device.turn_on_channel(channel)
            else:
                if channel == '0':
                    device.turn_off()
                else:
                    device.turn_off_channel(channel)
        except:
            pass

    devices[d._uuid] = RefreshOneDevice(device)

    return devices
예제 #16
0
class MerossManager(object):
    @classmethod
    def from_email_and_password(cls,
                                meross_email,
                                meross_password,
                                discovery_interval=30.0,
                                auto_reconnect=True
                                ):
        cloud_creds = MerossHttpClient.login(email=meross_email, password=meross_password)
        return MerossManager(
            cloud_credentials=cloud_creds,
            discovery_interval=discovery_interval,
            auto_reconnect=auto_reconnect)

    def __init__(self, cloud_credentials, discovery_interval, auto_reconnect):
        self._cloud_creds = cloud_credentials
        self._http_client = MerossHttpClient(cloud_credentials=self._cloud_creds)

        self._devices_lock = lock_factory.build_rlock()
        self._devices = dict()
        self._event_callbacks_lock = lock_factory.build_rlock()
        self._event_callbacks = []

        # Instantiate the mqtt cloud client
        self._cloud_client = MerossCloudClient(cloud_credentials=self._cloud_creds,
                                               push_message_callback=self._dispatch_push_notification,
                                               auto_reconnect=auto_reconnect)
        self._cloud_client.connection_status.register_connection_event_callback(callback=self._fire_event)
        self._device_discoverer = None
        self._stop_discovery = Event()
        self._device_discovery_done = Event()
        self._discovery_interval = discovery_interval

    def list_http_devices(self):
        """
        Performs a listing of Meross Devices as reported by the HTTP API.
        """
        return self._http_client.list_devices()

    def start(self, wait_for_first_discovery=True):
        l.debug("Starting manager")
        # Connect to the mqtt broker
        self._cloud_client.connect()
        l.debug("Connection succeeded. Starting discovery...")
        if self._device_discoverer is None or not self._device_discoverer.is_alive():
            self._device_discoverer = Thread(target=self._device_discover_thread)
            self._device_discoverer.start()

        if wait_for_first_discovery:
            l.debug("Caller requested wait-for-first-discovery. Waiting...")
            self._device_discovery_done.wait()
        l.debug("Discovery done.")

    def stop(self, logout=False):
        l.debug("Stopping manager...")
        self._cloud_client.close()
        self._stop_discovery.set()
        self._device_discoverer.join()

        if logout:
            self._http_client.logout()

        l.debug("Stop done.")

    def _device_discover_thread(self):
        while True:
            try:
                self._discover_devices(online_only=False)
            finally:
                if self._stop_discovery.wait(self._discovery_interval):
                    self._stop_discovery.clear()
                    break

    def register_event_handler(self, callback):
        with self._event_callbacks_lock:
            if callback in self._event_callbacks:
                pass
            else:
                self._event_callbacks.append(callback)

    def unregister_event_handler(self, callback):
        with self._event_callbacks_lock:
            if callback not in self._event_callbacks:
                pass
            else:
                self._event_callbacks.remove(callback)

    def get_device_by_uuid(self, uuid):
        self._ensure_started()

        dev = None
        with self._devices_lock:
            dev = self._devices.get(uuid)

        return dev

    def get_device_by_name(self, name):
        self._ensure_started()

        with self._devices_lock:
            for k, v in self._devices.items():
                if v.name.lower() == name.lower():
                    return v
        return None

    def get_supported_devices(self):
        self._ensure_started()
        return [x for k, x in self._devices.items()]

    def get_devices_by_kind(self, clazz):
        self._ensure_started()
        res = []
        with self._devices_lock:
            for k, v in self._devices.items():
                if isinstance(v, clazz):
                    res.append(v)
        return res

    def get_devices_by_type(self, type_name):
        self._ensure_started()
        res = []
        with self._devices_lock:
            for k, v in self._devices.items():
                if v.type.lower() == type_name.lower():
                    res.append(v)
        return res

    def _dispatch_push_notification(self, message, from_myself=False):
        """
        When a push notification is received from the MQTT client, it needs to be delivered to the
        corresponding device. This method serves that scope.
        :param message:
        :param from_myself: boolean flag. When True, it means that the message received is related to a
        previous request issued by this client. When is false, it means the message is related to some other
        client.
        :return:
        """
        header = message['header']      # type: dict
        payload = message['payload']    # type: dict

        # Identify the UUID of the target device by looking at the FROM field of the message header
        dev_uuid = header['from'].split('/')[2]

        # Let's intercept the Bind events: they are useful to trigger new device discovery
        namespace = header.get('namespace')

        # TODO: The following has been commented because it may trigger a recursive events-loop. This is not strictly
        #  necessary here, so just avoid doing so.
        #if namespace is not None and namespace in [BIND, ONLINE]:
        #    self._discover_devices()

        # Let's find the target of the event so that it can handle accordingly
        device = None
        with self._devices_lock:
            device = self._devices.get(dev_uuid)

        if device is not None:
            device.handle_push_notification(namespace, payload, from_myself=from_myself)
        else:
            # If we receive a push notification from a device that is not yet contained into our registry,
            # it probably means a new one has just been registered with the meross cloud.
            # This should never happen as we handle the "bind" event just above. However, It appears that the report
            # event is fired before the BIND event. So we need to ignore it at this point
            if namespace == REPORT:
                l.info("Ignoring REPORT event from device %s" % dev_uuid)
            else:
                l.warn("An event was received from an unknown device, which did not trigger the BIND event. "
                       "Device UUID: %s, namespace: %s." % (dev_uuid, namespace))

    def _discover_devices(self, online_only=False):
        """
        Discovers the devices that are visible via HTTP API and update the internal list of
        managed devices accordingly.
        :return:
        """
        for dev in self._http_client.list_devices():
            online = dev['onlineStatus']

            if online_only and online != 1:
                # The device is not online, so we skip it.
                continue

            # If the device we have discovered is not in the list we already handle, we need to add it.
            discovered = self._handle_device_discovered(dev)

            # If the specific device is an HUB, add all its sub devices
            if isinstance(discovered, GenericHub):
                for subdev in self._http_client.list_hub_subdevices(discovered.uuid):
                    self._handle_device_discovered(dev=subdev, parent_hub=discovered)

        self._device_discovery_done.set()

        return self._devices

    def _handle_device_unbound(self, dev_uuid):
        with self._devices_lock:
            if dev_uuid in self._devices:
                l.info("Unregistering device %s" % dev_uuid)
                del self._devices[dev_uuid]

    def _handle_device_discovered(self, dev, parent_hub=None):
        device = None

        # Check whether we are dealing with a full device or with a subdevice
        if 'deviceType' in dev and 'uuid' in dev:
            # FULL DEVICE case
            d_type = dev['deviceType']
            d_id = dev['uuid']
            device_id = d_id
            with self._devices_lock:
                if device_id not in self._devices:
                    device = build_wrapper(device_type=d_type, device_uuid=d_id,
                                           cloud_client=self._cloud_client, device_specs=dev)
                    self._devices[device_id] = device
            is_subdevice = False

        elif 'subDeviceType' in dev and 'subDeviceId' in dev:
            # SUB DEVICE case
            d_type = dev['subDeviceType']
            d_id = dev['subDeviceId']
            device_id = "%s:%s" % (parent_hub.uuid, d_id)
            with self._devices_lock:
                if device_id not in self._devices:
                    device = build_subdevice_wrapper(device_type=d_type, device_id=d_id, parent_hub=parent_hub,
                                                     cloud_client=self._cloud_client, device_specs=dev)
                    self._devices[device_id] = device
            is_subdevice = True

        else:
            l.warn("Discovered device does not seem to be either a full device nor a subdevice.")
            return

        if device is not None:
            # If this device was not in the list before, register the event handler for it and fire the ONLINE event.
            with self._event_callbacks_lock:
                for c in self._event_callbacks:
                    device.register_event_callback(c)
            return device
        else:
            # If the device already existed, fire an ONLINE event if the device online status has changed
            old_dev = self._devices.get(device_id)
            new_online_status = dev.get('onlineStatus', 2)

            # TODO: Fix this workaround...
            #  Emulate the push notification
            payload = {'online': {'status': new_online_status}}
            old_dev.handle_push_notification(ONLINE, payload)
            # if device was unchanged, return reference to existing instance
            return old_dev

            # TODO: handle subdevices

    def _fire_event(self, eventobj):
        for c in self._event_callbacks:
            try:
                c(eventobj)
            except:
                l.exception("An unhandled error occurred while invoking callback")

    def _ensure_started(self):
        if not self._cloud_client.connection_status.check_status(ClientStatus.SUBSCRIBED):
            l.warn("The manager is not connected to the mqtt broker. Did you start the Meross manager?")
예제 #17
0
from meross_iot.api import MerossHttpClient
import csv, io

EMAIL = 'YOUR_EMAIL'
PASSWORD = '******'

client = MerossHttpClient(email=EMAIL, password=PASSWORD)
devices = client.list_supported_devices()


def sanitize_personal_info(d):
    if isinstance(d, dict):
        for key, value in d.items():
            k = key.lower()

            if isinstance(value, dict):
                sanitize_personal_info(value)
            elif isinstance(value, str) and (k == 'uuid' or k == 'macaddress'
                                             or k == 'wifimac' or k == 'userid'
                                             or k == 'bssid' or k == 'ssid'):
                d[key] = 'X'
    elif isinstance(d, list):
        for k in d:
            sanitize_personal_info(k)

    return d


if __name__ == '__main__':
    output = io.StringIO()
    writer = csv.writer(output, delimiter=';')
예제 #18
0
 def _test_authorization(username, password):
     client = MerossHttpClient.from_user_password(email=username,
                                                  password=password)
     return client.get_cloud_credentials()
예제 #19
0
class MerossManager(object):
    # HTTPClient object used to discover devices
    _http_client = None

    # Dictionary of devices that are currently handled by this manager
    # as UUID -> Device
    _devices = None

    # Lock item used to protect access to the device collection
    _devices_lock = None

    # Cloud credentials to be used against the Meross MQTT cloud
    _cloud_creds = None

    _cloud_client = None

    # List of callbacks that should be called when an event occurs
    _event_callbacks = None
    _event_callbacks_lock = None

    def __init__(self, meross_email, meross_password):
        self._devices_lock = RLock()
        self._devices = dict()
        self._event_callbacks_lock = RLock()
        self._event_callbacks = []

        self._http_client = MerossHttpClient(email=meross_email, password=meross_password)
        self._cloud_creds = self._http_client.get_cloud_credentials()

        # Instantiate the mqtt cloud client
        self._cloud_client = MerossCloudClient(cloud_credentials=self._cloud_creds,
                                               push_message_callback=self._dispatch_push_notification)
        self._cloud_client.connection_status.register_connection_event_callback(callback=self._fire_event)

    def start(self):
        # Connect to the mqtt broker
        self._cloud_client.connect()
        self._discover_devices()

    def stop(self):
        self._cloud_client.close()

    def register_event_handler(self, callback):
        with self._event_callbacks_lock:
            if callback in self._event_callbacks:
                pass
            else:
                self._event_callbacks.append(callback)

    def unregister_event_handler(self, callback):
        with self._event_callbacks_lock:
            if callback not in self._event_callbacks:
                pass
            else:
                self._event_callbacks.remove(callback)

    def get_device_by_uuid(self, uuid):
        self._ensure_started()

        dev = None
        with self._devices_lock:
            dev = self._devices.get(uuid)

        return dev

    def get_device_by_name(self, name):
        self._ensure_started()

        with self._devices_lock:
            for k, v in self._devices.items():
                if v.name.lower() == name.lower():
                    return v
        return None

    def get_supported_devices(self):
        self._ensure_started()
        return [x for k, x in self._devices.items()]

    def get_devices_by_kind(self, clazz):
        self._ensure_started()
        res = []
        with self._devices_lock:
            for k, v in self._devices.items():
                if isinstance(v, clazz):
                    res.append(v)
        return res

    def get_devices_by_type(self, type_name):
        self._ensure_started()
        res = []
        with self._devices_lock:
            for k, v in self._devices.items():
                if v.type.lower() == type_name.lower():
                    res.append(v)
        return res

    def _dispatch_push_notification(self, message, from_myself=False):
        """
        When a push notification is received from the MQTT client, it needs to be delivered to the
        corresponding device. This method serves that scope.
        :param message:
        :param from_myself: boolean flag. When True, it means that the message received is related to a
        previous request issued by this client. When is false, it means the message is related to some other
        client.
        :return:
        """
        header = message['header']      # type: dict
        payload = message['payload']    # type: dict

        # Identify the UUID of the target device by looking at the FROM field of the message header
        dev_uuid = header['from'].split('/')[2]
        device = None
        with self._devices_lock:
            device = self._devices.get(dev_uuid)

        if device is not None:
            namespace = header['namespace']
            device.handle_push_notification(namespace, payload, from_myself=from_myself)
        else:
            # If we receive a push notification from a device that is not yet contained into our registry,
            # it probably means a new one has just been registered with the meross cloud.
            # Therefor, let's retrieve info from the HTTP api.
            self._discover_devices()

    def _discover_devices(self, online_only=False):
        """
        Discovers the devices that are visible via HTTP API and update the internal list of
        managed devices accordingly.
        :return:
        """
        for dev in self._http_client.list_devices():
            online = dev['onlineStatus']

            if online_only and online != 1:
                # The device is not online, so we skip it.
                continue

            # If the device we have discovered is not in the list we already handle, we need to add it.
            discovered = self._handle_device_discovered(dev)

            # If the specific device is an HUB, add all its sub devices
            if isinstance(discovered, GenericHub):
                for subdev in self._http_client.list_hub_subdevices(discovered.uuid):
                    self._handle_device_discovered(dev=subdev, parent_hub=discovered)

        return self._devices

    def _handle_device_discovered(self, dev, parent_hub=None):
        device = None

        # Check whether we are dealing with a full device or with a subdevice
        if 'deviceType' in dev and 'uuid' in dev:
            # FULL DEVICE case
            d_type = dev['deviceType']
            d_id = dev['uuid']
            device_id = d_id
            device = build_wrapper(device_type=d_type, device_uuid=d_id,
                                   cloud_client=self._cloud_client, device_specs=dev)
        elif 'subDeviceType' in dev and 'subDeviceId' in dev:
            # SUB DEVICE case
            d_type = dev['subDeviceType']
            d_id = dev['subDeviceId']
            device_id = "%s:%s" % (parent_hub.uuid, d_id)
            device = build_subdevice_wrapper(device_type=d_type, device_id=d_id, parent_hub=parent_hub,
                                   cloud_client=self._cloud_client, device_specs=dev)
        else:
            l.warn("Discovered device does not seem to be either a full device nor a subdevice.")
            return

        if device is not None:
            # Check if the discovered device is already in the list of handled devices.
            # If not, add it right away. Otherwise, ignore it.
            is_new = False
            with self._devices_lock:
                if d_id not in self._devices:
                    is_new = True
                    self._devices[device_id] = device

            # If this is new device, register the event handler for it and fire the ONLINE event.
            if is_new:
                with self._event_callbacks_lock:
                    for c in self._event_callbacks:
                        device.register_event_callback(c)

                evt = DeviceOnlineStatusEvent(device, device.online)
                self._fire_event(evt)

        return device

    def _fire_event(self, eventobj):
        for c in self._event_callbacks:
            try:
                c(eventobj)
            except:
                l.exception("An unhandled error occurred while invoking callback")

    def _ensure_started(self):
        if not self._cloud_client.connection_status.check_status(ClientStatus.SUBSCRIBED):
            l.warn("The manager is not connected to the mqtt broker. Did you start the Meross manager?")
예제 #20
0
 def setUp(self):
     self.client = MerossHttpClient(email=EMAIL, password=PASSWORD)
예제 #21
0
#!/usr/bin/env python3.6

from sys import argv
from meross_iot.api import MerossHttpClient

mDev = int(argv[1])
mCh  = argv[2]          # ch 1-2-3-USB
mVal = int(argv[3])     # 0 = Off / 1 = On

print("parametri:" + argv[1] + " / " + argv[2] + " / " + argv[3])

mConnect = MerossHttpClient(email="YOUR REGISTERED EMAIL", password="******")
mDevices = mConnect.list_supported_devices()

if mCh != "USB":
        mCh = int(mCh)
        if mVal == 0:
                mDevices[mDev].turn_off_channel(mCh)
        else:
                mDevices[mDev].turn_on_channel(mCh)
else:
        if int(mVal) == 0:
                print("DISABILITA USB")
                mDevices[mDev].disable_usb()
        else:
                print("ABILITA USB")
                mDevices[mDev].enable_usb()
예제 #22
0
    devices = CLIENT.list_supported_devices()
    result = []

    for device in devices:
      result.append({
        'name': device._name,
        'isOn': device.get_status(0)
      })

    return result

  elif commandName == 'turn-device-on':
    for device in CLIENT.list_supported_devices():
      if device._name == props['deviceName']:
        device.turn_on()

  elif commandName == 'turn-device-off':
    for device in CLIENT.list_supported_devices():
      if device._name == props['deviceName']:
        device.turn_off()

  return {}

if __name__ == '__main__':
  CLIENT = MerossHttpClient(email=MEROSS_EMAIL, password=MEROSS_PASSWORD)

  def handler(data, callback):
    callback(handleInput(data))

  on_message(handler)
예제 #23
0
import time
import sys
from meross_iot.api import MerossHttpClient
from time import sleep
from passwords import *

if __name__=='__main__':
	httpHandler = MerossHttpClient(email=meross_email, password=meross_password)

	# Retrieves the list of supported devices
	devices = httpHandler.list_supported_devices()
	plug = devices[0]
	while True:
		print(plug.get_electricity()['electricity']['power'])
		sleep(1)
예제 #24
0
from meross_iot.api import MerossHttpClient
from meross_iot.supported_devices.power_plugs import GenericPlug
from meross_iot.supported_devices.light_bulbs import GenericBulb
import secret

httpHandler = MerossHttpClient(email=secret.email, password=secret.password)
device = httpHandler.list_supported_devices()[0]


def turnOn():
    device.turn_on_channel(0)


def turnOff():
    device.turn_off_channel(0)


def getPowerConsumption():
    return device.get_power_consumption()


def getElectricityConsumption():
    return device.get_electricity()


if __name__ == '__main__':

    httpHandler = MerossHttpClient(email="*****@*****.**",
                                   password="******")
    print("Listing online devices...")
예제 #25
0
 def setUp(self):
     self.client = MerossHttpClient.from_user_password(email=EMAIL,
                                                       password=PASSWORD)