Esempio n. 1
0
    def set_hostname(self, hostname):
        """
        Set raspi hostname

        Args:
            hostname (string): hostname

        Returns:
            bool: True if hostname saved successfully, False otherwise

        Raises:
            InvalidParameter: if hostname has invalid format
        """
        # check hostname
        if re.match(self.__hostname_pattern, hostname) is None:
            raise InvalidParameter("Hostname is not valid")

        # update hostname
        res = self.hostname.set_hostname(hostname)

        # send event to update hostname on all devices
        if res:
            self.hostname_update_event.send(params={"hostname": hostname})

        return res
Esempio n. 2
0
    def install_driver(self, driver_type, driver_name, force=False):
        """
        Install specified driver.
        If install succeed, device will reboot after a delay

        Args:
            driver_type (string): driver type
            driver_name (string): driver name
            force (bool): force install (repair)

        Raises:
            MissingParameter: if a parameter is missing
            InvalidParameter: if driver was not found
            CommandInfo: if driver already installed
        """
        self._check_parameters([
            {
                'name': 'driver_type',
                'type': str,
                'value': driver_type
            },
            {
                'name': 'driver_name',
                'type': str,
                'value': driver_name
            },
            {
                'name': 'force',
                'type': bool,
                'value': force
            },
        ])

        # get driver
        driver = self.drivers.get_driver(driver_type, driver_name)
        if not driver:
            raise InvalidParameter('No driver found for specified parameters')

        if not force and driver.is_installed():
            raise CommandInfo('Driver is already installed')

        # launch installation (non blocking) and send event
        driver.install(self._install_driver_terminated, logger=self.logger)
        self.driver_install_event.send({
            'drivertype': driver_type,
            'drivername': driver_name,
            'installing': True,
            'success': None,
            'message': None,
        })
Esempio n. 3
0
    def update_gpio(self, device_uuid, name, keep, inverted, command_sender):
        """
        Update gpio

        Args:
            device_uuid (string): device identifier
            name (string): gpio name
            keep (bool): keep status flag
            inverted (bool): inverted flag
            command_sender (string): command sender

        Returns:
            dict: updated gpio device

        Raises:
            CommandError
            MissingParameter
            Unauthorized
            InvalidParameter
        """
        # fix command_sender: rpcserver is the default gpio entry point
        if command_sender == "rpcserver":
            command_sender = "gpios"

        # check values
        self._check_parameters(
            [
                {"name": "device_uuid", "value": device_uuid, "type": str},
                {"name": "name", "value": name, "type": str},
                {"name": "keep", "value": keep, "type": bool},
                {"name": "inverted", "value": inverted, "type": bool},
            ]
        )
        device = self._get_device(device_uuid)
        if device is None:
            raise InvalidParameter('Device "%s" does not exist' % device_uuid)
        if device["owner"] != command_sender:
            raise Unauthorized("Device can only be updated by its owner")

        # device is valid, update entry
        device["name"] = name
        device["keep"] = keep
        device["inverted"] = inverted
        if not self._update_device(device_uuid, device):
            raise CommandError('Failed to update device "%s"' % device["uuid"])

        # relaunch watcher
        self._reconfigure_gpio(device)

        return device
Esempio n. 4
0
    def set_position(self, latitude, longitude):
        """
        Set device position

        Args:
            latitude (float): latitude
            longitude (float): longitude

        Raises:
            CommandError: if error occured during position saving
        """
        if latitude is None:
            raise MissingParameter('Parameter "latitude" is missing')
        if not isinstance(latitude, float):
            raise InvalidParameter('Parameter "latitude" is invalid')
        if longitude is None:
            raise MissingParameter('Parameter "longitude" is missing')
        if not isinstance(longitude, float):
            raise InvalidParameter('Parameter "longitude" is invalid')

        # save new position
        position = {"latitude": latitude, "longitude": longitude}

        if not self._set_config_field("position", position):
            raise CommandError("Unable to save position")

        # reset python time to take into account last modifications before
        # computing new times
        time.tzset()

        # and update related stuff
        self.set_timezone()
        self.set_country()
        self.set_sun()

        # send now event
        self._time_task()
Esempio n. 5
0
    def uninstall_driver(self, driver_type, driver_name):
        """
        Uninstall specified driver.
        If uninstall succeed, device will reboot after a delay.

        Args:
            driver_type (string): driver type
            driver_name (string): driver name

        Raises:
            MissingParameter: if a parameter is missing
            InvalidParameter: if driver was not found
            CommandInfo: if driver is not installed
        """
        self._check_parameters([
            {
                'name': 'driver_type',
                'type': str,
                'value': driver_type
            },
            {
                'name': 'driver_name',
                'type': str,
                'value': driver_name
            },
        ])

        # get driver instance
        driver = self.drivers.get_driver(driver_type, driver_name)
        if not driver:
            raise InvalidParameter('No driver found for specified parameters')

        if not driver.is_installed():
            raise CommandInfo('Driver is not installed')

        # launch uninstallation (non blocking) and send event
        driver.uninstall(self._uninstall_driver_terminated, logger=self.logger)
        self.driver_uninstall_event.send({
            'drivertype': driver_type,
            'drivername': driver_name,
            'uninstalling': True,
            'success': None,
            'message': None,
        })

        return True
Esempio n. 6
0
    def check_application(self, module_name):
        """
        Check application content

        Args:
            module_name (string): module name

        Returns:
            dict: archive infos::

                {
                    url (string): archive url,
                    name (string): archive name (usually name of module)
                }

        """
        # check parameters
        if module_name is None or len(module_name) == 0:
            raise MissingParameter('Parameter "module_name" is missing')
        module_path = os.path.join(self.cleep_path, 'modules', module_name,
                                   '%s.py' % module_name)
        if not os.path.exists(module_path):
            raise InvalidParameter('Module "%s" does not exist' % module_name)

        # execute checks
        backend_result = self.__cli_check(self.CLI_CHECK_BACKEND_CMD %
                                          (self.CLI, module_name))
        frontend_result = self.__cli_check(self.CLI_CHECK_FRONTEND_CMD %
                                           (self.CLI, module_name))
        scripts_result = self.__cli_check(self.CLI_CHECK_SCRIPTS_CMD %
                                          (self.CLI, module_name))
        tests_result = self.__cli_check(self.CLI_CHECK_TESTS_CMD %
                                        (self.CLI, module_name))
        # code_result = self.__cli_check(self.CLI_CHECK_CODE_CMD % (self.CLI, module_name))
        changelog_result = self.__cli_check(self.CLI_CHECK_CHANGELOG_CMD %
                                            (self.CLI, module_name))

        return {
            'backend': backend_result,
            'frontend': frontend_result,
            'scripts': scripts_result,
            'tests': tests_result,
            'changelog': changelog_result,
            # 'quality': code_result,
        }
Esempio n. 7
0
    def delete_gpio(self, device_uuid, command_sender):
        """
        Delete gpio

        Args:
            uuid: device identifier
            command_sender (string): command sender

        Returns:
            bool: True if device was deleted, False otherwise

        Raises:
            CommandError
            MissingParameter
            Unauthorized
            InvalidParameter
        """
        # fix command_sender: rpcserver is the default gpio entry point
        if command_sender == "rpcserver":
            command_sender = "gpios"

        # check values
        self._check_parameters(
            [
                {"name": "device_uuid", "value": device_uuid, "type": str},
            ]
        )
        device = self._get_device(device_uuid)
        if device is None:
            raise InvalidParameter('Device "%s" does not exist' % device_uuid)
        if device["owner"] != command_sender:
            raise Unauthorized("Device can only be deleted by its owner")

        # device is valid, remove entry
        if not self._delete_device(device_uuid):
            raise CommandError('Failed to delete device "%s"' % device["uuid"])

        self._deconfigure_gpio(device)

        return True
Esempio n. 8
0
    def add(self, name, gpio, interval, offset, offset_unit):
        """
        Return sensor data to add.
        Can perform specific stuff

        Args:
            name (string): sensor name
            gpio (string): gpio name
            interval (int): interval value
            offset (int): offset value
            offset_unit (string): offset unit

        Returns:
            dict: sensor data to add::

                {
                    gpios (list): list of gpios data to add
                    sensors (list): list sensors data to add
                }

        """
        # get assigned gpios
        assigned_gpios = self._get_assigned_gpios()

        # check parameters
        self._check_parameters([
            {
                "name": "name",
                "value": name,
                "type": str,
                "validator":
                lambda val: self._search_device("name", val) is None,
                "message": 'Name "%s" is already used' % name,
            },
            {
                "name": "gpio",
                "value": gpio,
                "type": str,
                "validator": lambda val: gpio not in assigned_gpios,
                "message": 'Gpio "%s" is already used' % gpio,
            },
            {
                "name": "interval",
                "value": interval,
                "type": int,
                "validator": lambda val: val >= 60,
                "message": "Interval must be greater or equal than 60",
            },
            {
                "name": "offset",
                "value": offset,
                "type": int,
            },
            {
                "name":
                "offset_unit",
                "value":
                offset_unit,
                "type":
                str,
                "validator":
                lambda val: val in
                (SensorsUtils.TEMP_CELSIUS, SensorsUtils.TEMP_FAHRENHEIT),
                "message":
                'Offset_unit value must be either "celsius" or "fahrenheit"',
            },
        ])
        # TODO add new validator in cleep v0.0.27
        if gpio not in self.raspi_gpios:
            raise InvalidParameter(
                'Gpio "%s" does not exist for this raspberry pi' % gpio)

        gpio_data = {
            "name": name + "_dht22",
            "gpio": gpio,
            "mode": "input",
            "keep": False,
            "inverted": False,
        }

        temperature_data = {
            "name": name,
            "gpios": [],
            "type": self.TYPE_TEMPERATURE,
            "subtype": self.SUBTYPE,
            "interval": interval,
            "offset": offset,
            "offsetunit": offset_unit,
            "lastupdate": int(time.time()),
            "celsius": None,
            "fahrenheit": None,
        }

        humidity_data = {
            "name": name,
            "gpios": [],
            "type": self.TYPE_HUMIDITY,
            "subtype": self.SUBTYPE,
            "interval": interval,
            "lastupdate": int(time.time()),
            "humidity": None,
        }

        return {
            "gpios": [
                gpio_data,
            ],
            "sensors": [
                temperature_data,
                humidity_data,
            ],
        }
Esempio n. 9
0
    def select_device(self, driver_name):
        """
        Select audio device

        Args:
            driver_name (string): driver name

        Returns:
            bool: True if device saved successfully

        Raises:
            InvalidParameter: if parameter is invalid
        """
        # check params
        self._check_parameters(
            [
                {"name": "driver_name", "type": str, "value": driver_name},
                {
                    "name": "driver_name",
                    "type": str,
                    "value": driver_name,
                    "validator": lambda val: driver_name
                    != self._get_config_field("driver"),
                    "message": f'Device "{driver_name}" is already selected',
                },
            ]
        )

        # get drivers
        selected_driver_name = self._get_config_field("driver")
        old_driver = (
            self.drivers.get_driver(Driver.DRIVER_AUDIO, selected_driver_name)
            if selected_driver_name is not None
            else None
        )
        new_driver = self.drivers.get_driver(Driver.DRIVER_AUDIO, driver_name)

        if not new_driver:
            raise InvalidParameter("Specified driver does not exist")
        if not new_driver.is_installed():
            raise InvalidParameter(
                "Can't selected device because its driver seems not to be installed"
            )

        # disable old driver
        self.logger.info('Using audio driver "%s"', new_driver.name)
        if old_driver and old_driver.is_installed():
            disabled = old_driver.disable()
            self.logger.debug(
                'Disable previous driver "%s": %s', old_driver.name, disabled
            )
            if not disabled:
                raise CommandError("Unable to disable current driver")

        # enable new driver
        self.logger.debug('Enable new driver "%s"', new_driver.name)
        driver_enabled = new_driver.enable()
        if not driver_enabled or not new_driver.is_card_enabled():
            self.logger.info(
                "Unable to enable selected driver. Revert re-enabling previous driver"
            )
            if old_driver:
                old_driver.enable()
            raise CommandError("Unable to enable selected device")

        # everything is fine, save new driver
        self._set_config_field("driver", new_driver.name)

        # restart cleep
        self.send_command("restart_cleep", "system")
    def add(self, name, gpio, inverted):
        """
        Return sensor data to add.
        Can perform specific stuff

        Args:
            name (string): sensor name
            gpio (string): used gpio
            inverted (bool): True if gpio is inverted

        Returns:
            dict: sensor data to add::

                {
                    gpios (list): list of gpios data to add
                    sensors (list): list sensors data to add
                }

        """
        # get assigned gpios
        assigned_gpios = self._get_assigned_gpios()

        # check values
        self._check_parameters([
            {
                'name': 'name',
                'value': name,
                'type': str,
                'validator':
                lambda val: self._search_device("name", name) is None,
                'message': 'Name "%s" is already used' % name,
            },
            {
                'name': 'gpio',
                'value': gpio,
                'type': str,
                'validator': lambda val: gpio not in assigned_gpios,
                'message': 'Gpio "%s" is already used' % gpio,
            },
            {
                'name': 'inverted',
                'value': inverted,
                'type': bool
            },
        ])
        # TODO add new validator in cleep v0.0.27
        if gpio not in self.raspi_gpios:
            raise InvalidParameter(
                'Gpio "%s" does not exist for this raspberry pi' % gpio)

        # configure gpio
        gpio_data = {
            "name": name + "_motion",
            "gpio": gpio,
            "mode": "input",
            "keep": False,
            "inverted": inverted,
        }

        sensor_data = {
            "name": name,
            "gpios": [],
            "type": self.TYPE_MOTION,
            "subtype": self.SUBTYPE,
            "on": False,
            "inverted": inverted,
            "lastupdate": 0,
            "lastduration": 0,
        }

        # read current gpio value
        resp = self.send_command("is_gpio_on", "gpios", {"gpio": gpio})
        if not resp.error:
            sensor_data["on"] = resp.data
        sensor_data["lastupdate"] = int(time.time())

        return {
            "gpios": [
                gpio_data,
            ],
            "sensors": [
                sensor_data,
            ],
        }
Esempio n. 11
0
    def reserve_gpio(self, name, gpio, usage, command_sender):
        """
        Reserve a gpio used to configure raspberry pi (ie onewire, lirc...)
        This action only flag this gpio as reserved to avoid using it again

        Args:
            name (string): name of gpio
            gpio (string) : gpio value
            usage (string) : describe gpio usage
            command_sender (string): command request sender (used to set gpio in readonly mode)

        Returns:
            dict: Created gpio device

        Raises:
            CommandError
            MissingParameter
            InvalidParameter
        """
        # fix command_sender: rpcserver is the default gpio entry point
        if command_sender == "rpcserver":
            command_sender = "gpios"

        # check values
        if gpio:
            found_gpio = self._search_device("gpio", gpio)
            if found_gpio is not None and found_gpio["subtype"] != usage:
                raise InvalidParameter(
                    'Gpio "%s" is already reserved for "%s" usage'
                    % (found_gpio["gpio"], found_gpio["subtype"])
                )
            if found_gpio is not None and found_gpio["subtype"] == usage:
                return found_gpio
        self._check_parameters(
            [
                {
                    "name": "name",
                    "value": name,
                    "type": str,
                    "validator": lambda val: self._search_device("name", val) is None,
                    "message": 'Name "%s" is already used' % name,
                },
                {
                    "name": "gpio",
                    "value": gpio,
                    "type": str,
                    "validator": lambda val: val in self.get_raspi_gpios().keys(),
                    "message": 'Gpio "%s" does not exist for this raspberry pi' % gpio,
                },
                {"name": "usage", "value": usage, "type": str},
            ]
        )

        # gpio is valid, prepare new entry
        data = {
            "name": name,
            "mode": self.MODE_RESERVED,
            "pin": self.get_raspi_gpios()[gpio],
            "gpio": gpio,
            "keep": False,
            "on": False,
            "inverted": False,
            "owner": command_sender,
            "type": "gpio",
            "subtype": usage,
        }

        # add device
        self.logger.debug("data=%s" % data)
        device = self._add_device(data)
        if device is None:
            raise CommandError("Unable to add device")

        return device
Esempio n. 12
0
    def update_sensor(self, sensor_uuid, data):
        """
        Update sensor

        Args:
            sensor_uuid (string): sensor uuid
            data (dict): sensor data

        Returns:
            list: list of updated sensors
        """
        if not sensor_uuid:
            raise MissingParameter("Uuid parameter is missing")
        sensor = self._get_device(sensor_uuid)
        if sensor is None:
            raise InvalidParameter('Sensor with uuid "%s" doesn\'t exist' %
                                   sensor_uuid)

        # search addon
        addon = self._get_addon(sensor["type"], sensor["subtype"])
        if addon is None:
            raise CommandError('Unhandled sensor type "%s-%s"' %
                               (sensor["type"], sensor["subtype"]))

        sensor_devices = []
        gpio_devices = []
        try:
            # prepare data mixing all params from all sensors
            data["sensor"] = sensor
            (gpios, sensors) = addon.update(**data).values()
            if not isinstance(gpios, list) or not isinstance(
                    sensors, list):  # pragma: no cover
                raise Exception(
                    "Invalid gpios or sensors type. Must be a list")

            # update gpios
            for gpio in gpios:
                resp_gpio = self.send_command("update_gpio", "gpios",
                                              self._fix_gpio_device(gpio))
                if resp_gpio.error:
                    raise CommandError(resp_gpio.message)
                gpio_devices.append(resp_gpio.data)

            # update sensors
            for sensor in sensors:
                if not self._update_device(sensor["uuid"], sensor):
                    raise CommandError("Unable to update sensor")
                sensor_devices.append(sensor)

            # restart sensor task
            task = addon.get_task(sensor)
            if task:
                self._stop_sensor_task(sensor)
                self._start_sensor_task(task, [sensor])

            return sensor_devices

        except Exception as error:
            self.logger.exception('Error occured updating sensor "%s": %s' %
                                  (sensor_uuid, data))
            raise CommandError("Error updating sensor") from error
Esempio n. 13
0
    def delete_sensor(self, sensor_uuid):
        """
        Delete specified sensor

        Args:
            sensor_uuid (string): sensor identifier

        Returns:
            bool: True if deletion succeed
        """
        if not sensor_uuid:
            raise MissingParameter("Uuid parameter is missing")
        sensor = self._get_device(sensor_uuid)
        if sensor is None:
            raise InvalidParameter('Sensor with uuid "%s" doesn\'t exist' %
                                   sensor_uuid)

        # search addon
        addon = self._get_addon(sensor["type"], sensor["subtype"])
        if addon is None:
            raise CommandError('Unhandled sensor type "%s-%s"' %
                               (sensor["type"], sensor["subtype"]))

        try:
            # stop task
            self._stop_sensor_task(sensor)

            (gpios, sensors) = addon.delete(sensor).values()
            if not isinstance(gpios, list) or not isinstance(
                    sensors, list):  # pragma: no cover
                raise Exception(
                    "Invalid gpios or sensors type. Must be a list")

            # unconfigure gpios
            self.logger.debug("Gpios=%s" % gpios)
            for gpio in gpios:
                # is a reserved gpio
                self.logger.debug('is_reserved_gpio for gpio "%s"' % gpio)
                resp = self.send_command("is_reserved_gpio", "gpios",
                                         {"gpio": gpio["uuid"]})
                self.logger.debug("is_reserved_gpio: %s" % resp)
                if resp.error:
                    raise CommandError(resp.message)
                reserved_gpio = resp.data

                # check if we can delete gpio
                delete_gpio = True
                if reserved_gpio:
                    # reserved gpio, don't delete it
                    delete_gpio = False
                elif self._get_gpio_uses(gpio["gpio"]) > 1:
                    # another device is using gpio, do not delete it in gpio module
                    self.logger.info(
                        "More than one sensor is using gpio, disable gpio deletion"
                    )
                    delete_gpio = False

                # delete device in gpio module
                if delete_gpio:
                    self.logger.debug('Delete gpio "%s" from gpios module' %
                                      gpio["uuid"])
                    resp = self.send_command("delete_gpio", "gpios",
                                             {"device_uuid": gpio["uuid"]})
                    if resp.error:
                        self.logger.warning("Gpio can't be deleted: %s" %
                                            resp.error)
                else:
                    self.logger.debug(
                        "Gpio device not deleted because other sensor is using it"
                    )

            # delete sensors
            for sensor in sensors:
                self._delete_device(sensor["uuid"])
                self.logger.debug('Sensor "%s" deleted successfully' %
                                  sensor["uuid"])

            return True

        except Exception as error:
            self.logger.exception('Error occured deleting sensor "%s":' %
                                  (sensor_uuid))
            raise CommandError("Error deleting sensor") from error