Пример #1
0
  def send_webhook(self,subject,message,files = []):
    url = subject.decode()
    webhook = terrariumUtils.parse_url(url)
    if not webhook:
      return

    try:
      message = ','.join(message.decode().split('\n'))
      message = '{' + message.replace(':False',':false').replace(':True',':true').replace('None','null').replace('\'','"') + '}'
      message = json.loads(message)

      if len(files) > 0:
        message['files'] = []

        for attachment in files:
          with open(attachment,'rb') as fp:
            attachment_data = fp.read()
            message['files'].append({'name' : os.path.basename(attachment), 'data' : b64encode(attachment_data).decode('utf-8')})

      headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
      r = requests.post(url, data=json.dumps(message), headers=headers)
      if r.status_code != 200:
        print('Error sending webhook to url \'\' with status code: {}'.format(url,r.status_code))

    except Exception as ex:
      print('send_webhook exception:')
      print(ex)
Пример #2
0
  def __checker(self):
    logger.info('Start terrariumPI door checker for door \'%s\'' % self.get_name())
    while True:
      current_status = None
      if self.get_hardware_type() == 'gpio':
        current_status = terrariumDoor.OPEN if GPIO.input(terrariumUtils.to_BCM_port_number(self.get_address())) else terrariumDoor.CLOSED

      elif self.get_hardware_type() == 'remote' and (int(time.time()) - self.__last_check) >= terrariumDoor.REMOTE_TIMEOUT:
        current_status = None
        url_data = terrariumUtils.parse_url(self.get_address())
        if url_data is False:
          logger.error('Remote url \'%s\' for door \'%s\' is not a valid remote source url!' % (self.get_address(),self.get_name()))
        else:
          data = terrariumUtils.get_remote_data(self.get_address())
          if data is not None:
            current_status = terrariumDoor.OPEN if terrariumUtils.is_true(data) else terrariumDoor.CLOSED
          else:
            logger.warning('Remote door \'%s\' got error from remote source \'%s\'' % (self.get_name(),self.get_address()))

        self.__last_check = int(time.time())

      logger.debug('Current door \'%s\' status: %s' % (self.get_name(),current_status))
      if current_status != self.get_status():
        logger.info('Door \'%s\' changed from %s to %s' % (self.get_name(),self.get_status(), current_status))
        self.set_status(current_status)
        if self.callback is not None:
          self.callback(self.get_data())

      sleep(terrariumDoor.CHECKER_TIMEOUT)
Пример #3
0
  def update(self):
    if 'remote' in self.get_hardware_type():
      url_data = terrariumUtils.parse_url(self.get_address())
      if url_data is False:
        logger.error('Remote url \'%s\' for switch \'%s\' is not a valid remote source url!' % (self.get_address(),self.get_name()))
      else:
        try:
          data = requests.get(self.get_address(),auth=(url_data['username'],url_data['password']),timeout=3)

          if data.status_code == 200:
            data = data.json()
            json_path = url_data['fragment'].split('/') if 'fragment' in url_data and url_data['fragment'] is not None else []

            for item in json_path:
              # Dirty hack to process array data....
              try:
                item = int(item)
              except Exception, ex:
                item = str(item)

              data = data[item]

            if 'remote' == self.get_hardware_type():
              self.set_state(terrariumUtils.is_true(data))
            elif 'remote-dimmer' == self.get_hardware_type():
              self.set_state(int(data))

          else:
            logger.warning('Remote switch \'%s\' got error from remote source \'%s\':' % (self.get_name(),self.get_address(),data.status_code))
Пример #4
0
  def get_hardware_state(self):
    data = None
    url_data = terrariumUtils.parse_url(self.get_address())
    if url_data is False:
      logger.error('Remote url \'%s\' for switch \'%s\' is not a valid remote source url!' % (self.get_address(),self.get_name()))
    else:
      data = terrariumUtils.get_remote_data(self.get_address())

    return terrariumPowerSwitch.ON if terrariumUtils.is_true(data) else terrariumPowerSwitch.OFF
    def __load_history_data(self):
        # Onecall API's are more expensive (max 1000 a day - 1 call per 2 minutes) so we update this at a lower frequency
        # Here we can do 1 hit a day. As the history is per hole full day at a time, and will not change anymore
        if self.__history_day is not None and self.__history_day == int(
                datetime.utcfromtimestamp(
                    int(datetime.now().timestamp()) +
                    self._data["timezone"]).strftime('%d')):
            return True

        start = time()
        self._data['history'] = []
        address = terrariumUtils.parse_url(self.address)
        for day in range(1, 3):
            now = int(datetime.now().timestamp()) + self._data["timezone"] - (
                day * 24 * 60 * 60)
            history_url = 'https://api.openweathermap.org/data/2.5/onecall/timemachine?lat={}&lon={}&units=metric&dt={}&appid={}&lang={}'.format(
                self._data['geo']['lat'], self._data['geo']['long'], now,
                address['query_params']['appid'],
                self._device['language'][0:2])
            data = terrariumUtils.get_remote_data(history_url)

            if data is None:
                continue

            for item in data['hourly']:
                self._data['history'].append({
                    'timestamp':
                    int(item["dt"] + self._data["timezone"]),
                    'temperature':
                    float(item['temp']),
                    'humidity':
                    float(item['humidity']),
                    'pressure':
                    float(item['pressure']),
                    'uvi':
                    float(item['uvi']),
                })

        self._data['history'] = sorted(self._data['history'],
                                       key=lambda d: d['timestamp'])
        self.__history_day = int(
            datetime.utcfromtimestamp(
                int(datetime.now().timestamp()) +
                self._data["timezone"]).strftime('%d'))

        logger.info(
            f'Loaded new historical weather data ({len(self._data["history"])} measurements) from {datetime.fromtimestamp(int(self._data["history"][0]["timestamp"]))} till {datetime.fromtimestamp(int(self._data["history"][len(self._data["history"])-1]["timestamp"]))} in {time()-start:.2f} seconds.'
        )
        return True
Пример #6
0
    def send_webhook(self, subject, message, files=[]):
        url = subject.decode()
        webhook = terrariumUtils.parse_url(url)
        if not webhook:
            return

        try:
            message = ','.join(message.decode().split('\n'))
            message = '{' + message.replace(':False', ':false').replace(
                ':True', ':true').replace('\'', '"') + '}'
            message = json.loads(message)

            headers = {
                'Content-type': 'application/json',
                'Accept': 'text/plain'
            }
            r = requests.post(url, data=json.dumps(message), headers=headers)
            if r.status_code != 200:
                print('Error sending webhook to url \'\' with status code: {}'.
                      format(url, r.status_code))

        except Exception as ex:
            print('send_webhook exception:')
            print(ex)
Пример #7
0
 def __init__(self, url):
     self.__url = None
     self.__value = None
     if terrariumUtils.parse_url(url) is not False:
         self.__url = url
Пример #8
0
    def update(self, force=False):
        now = datetime.datetime.now()
        if now - self.last_update > datetime.timedelta(
                seconds=terrariumSensor.UPDATE_TIMEOUT) or force:
            logger.debug(
                'Updating %s %s sensor \'%s\'' %
                (self.get_hardware_type(), self.get_type(), self.get_name()))
            old_current = self.get_current()
            current = None
            try:
                starttime = time.time()
                if 'remote' == self.get_hardware_type():
                    url_data = terrariumUtils.parse_url(self.get_address())
                    if url_data is False:
                        logger.error(
                            'Remote url \'%s\' for sensor \'%s\' is not a valid remote source url!'
                            % (self.get_address(), self.get_name()))
                    else:
                        data = terrariumUtils.get_remote_data(
                            self.get_address())
                        if data is not None:
                            current = float(data)
                        else:
                            logger.warning(
                                'Remote sensor \'%s\' got error from remote source \'%s\': %s'
                                % (self.get_name(), self.get_address(),
                                   data.status_code))

                elif 'hc-sr04' == self.get_hardware_type():
                    GPIO.output(
                        terrariumUtils.to_BCM_port_number(
                            self.sensor_address['TRIG']), False)
                    time.sleep(2)
                    GPIO.output(
                        terrariumUtils.to_BCM_port_number(
                            self.sensor_address['TRIG']), True)
                    time.sleep(0.00001)
                    GPIO.output(
                        terrariumUtils.to_BCM_port_number(
                            self.sensor_address['TRIG']), False)
                    pulse_start = time.time()
                    while GPIO.input(
                            terrariumUtils.to_BCM_port_number(
                                self.sensor_address['ECHO'])) == 0:
                        pulse_start = time.time()
                    pulse_end = time.time()
                    while GPIO.input(
                            terrariumUtils.to_BCM_port_number(
                                self.sensor_address['ECHO'])) == 1:
                        pulse_end = time.time()

                    pulse_duration = pulse_end - pulse_start
                    # https://www.modmypi.com/blog/hc-sr04-ultrasonic-range-sensor-on-the-raspberry-pi
                    # Measure in centimetre
                    current = round(pulse_duration * 17150, 2)

                elif 'sku-sen0161' == self.get_hardware_type():
                    # Do multiple measurements...
                    values = []
                    for counter in range(5):
                        analog_port = MCP3008(channel=int(self.get_address()))
                        # https://github.com/theyosh/TerrariumPI/issues/108
                        # We measure the values in volts already, so no deviding by 1000 as original script does
                        values.append((analog_port.value *
                                       (5000.0 / 1024.0)) * 3.3 + 0.1614)
                        time.sleep(0.2)

                    # sort values from low to high
                    values.sort()
                    # Calculate average. Exclude the min and max value. And therefore devide by 3
                    current = round((sum(values[1:-1]) / 3.0), 2)

                elif 'temperature' == self.get_type():
                    if self.get_hardware_type() == 'owfs':
                        current = float(self.sensor.temperature)

                    elif self.get_hardware_type() == 'w1':
                        data = ''
                        with open(
                                terrariumSensor.W1_BASE_PATH +
                                self.get_address() + '/w1_slave',
                                'r') as w1data:
                            data = w1data.read()

                        w1data = terrariumSensor.W1_TEMP_REGEX.search(data)
                        if w1data:
                            # Found data
                            current = float(w1data.group('value')) / 1000
                    elif self.get_hardware_type(
                    ) in terrariumSensor.VALID_DHT_SENSORS.keys():
                        time.sleep(2.1)
                        humidity, temperature = self.sensor.read_retry(
                            terrariumSensor.VALID_DHT_SENSORS[
                                self.get_hardware_type()],
                            float(
                                terrariumUtils.to_BCM_port_number(
                                    self.sensor_address)), 5)
                        if temperature is not None:
                            current = float(temperature)

                elif 'humidity' == self.get_type():
                    if self.get_hardware_type() == 'owfs':
                        current = float(self.sensor.humidity)

                    elif self.get_hardware_type() == 'w1':
                        # Not tested / No hardware to test with
                        pass

                    elif self.get_hardware_type(
                    ) in terrariumSensor.VALID_DHT_SENSORS.keys():
                        time.sleep(2.1)
                        humidity, temperature = self.sensor.read_retry(
                            terrariumSensor.VALID_DHT_SENSORS[
                                self.get_hardware_type()],
                            float(
                                terrariumUtils.to_BCM_port_number(
                                    self.sensor_address)), 5)
                        if humidity is not None:
                            current = float(humidity)

                if current is None or not (self.get_limit_min() <= current <=
                                           self.get_limit_max()):
                    # Invalid current value.... log and ingore
                    logger.warn(
                        'Measured value %s%s from %s sensor \'%s\' is outside valid range %.2f%s - %.2f%s in %.5f seconds.'
                        % (current, self.get_indicator(), self.get_type(),
                           self.get_name(), self.get_limit_min(),
                           self.get_indicator(), self.get_limit_max(),
                           self.get_indicator(), time.time() - starttime))

                else:
                    self.current = current
                    self.last_update = now
                    logger.info(
                        'Updated %s sensor \'%s\' from %.2f%s to %.2f%s in %.5f seconds'
                        % (self.get_type(), self.get_name(), old_current,
                           self.get_indicator(), self.get_current(),
                           self.get_indicator(), time.time() - starttime))
            except Exception, ex:
                print ex
                logger.exception(
                    'Error updating %s %s sensor \'%s\' with error:' %
                    (self.get_hardware_type(), self.get_type(),
                     self.get_name()))
Пример #9
0
    def update(self, force=False):
        now = datetime.datetime.now()
        if now - self.last_update > datetime.timedelta(
                seconds=terrariumSensor.UPDATE_TIMEOUT) or force:
            logger.debug(
                'Updating %s %s sensor \'%s\'' %
                (self.get_hardware_type(), self.get_type(), self.get_name()))
            old_current = self.get_current()
            current = None
            try:
                starttime = time.time()
                if 'remote' == self.get_hardware_type():
                    url_data = terrariumUtils.parse_url(self.get_address())
                    if url_data is False:
                        logger.error(
                            'Remote url \'%s\' for sensor \'%s\' is not a valid remote source url!'
                            % (self.get_address(), self.get_name()))
                    else:
                        data = requests.get(self.get_address(),
                                            auth=(url_data['username'],
                                                  url_data['password']),
                                            timeout=3)

                        if data.status_code == 200:
                            data = data.json()
                            json_path = url_data['fragment'].split(
                                '/') if 'fragment' in url_data and url_data[
                                    'fragment'] is not None else []

                            for item in json_path:
                                # Dirty hack to process array data....
                                try:
                                    item = int(item)
                                except Exception, ex:
                                    item = str(item)

                                data = data[item]
                            current = float(data)
                        else:
                            logger.warning(
                                'Remote sensor \'%s\' got error from remote source \'%s\': %s'
                                % (self.get_name(), self.get_address(),
                                   data.status_code))

                elif 'temperature' == self.get_type():
                    if self.get_hardware_type() == 'owfs':
                        current = float(self.sensor.temperature)

                    elif self.get_hardware_type() == 'w1':
                        data = ''
                        with open(
                                terrariumSensor.W1_BASE_PATH +
                                self.get_address() + '/w1_slave',
                                'r') as w1data:
                            data = w1data.read()

                        w1data = terrariumSensor.W1_TEMP_REGEX.search(data)
                        if w1data:
                            # Found data
                            current = float(w1data.group('value')) / 1000
                    elif self.get_hardware_type(
                    ) in terrariumSensor.VALID_DHT_SENSORS.keys():
                        humidity, temperature = self.sensor.read_retry(
                            terrariumSensor.VALID_DHT_SENSORS[
                                self.get_hardware_type()],
                            float(
                                terrariumUtils.to_BCM_port_number(
                                    self.sensor_address)), 5)
                        if temperature is not None:
                            current = float(temperature)

                elif 'humidity' == self.get_type():
                    if self.get_hardware_type() == 'owfs':
                        current = float(self.sensor.humidity)

                    elif self.get_hardware_type() == 'w1':
                        # Not tested / No hardware to test with
                        pass

                    elif self.get_hardware_type(
                    ) in terrariumSensor.VALID_DHT_SENSORS.keys():
                        humidity, temperature = self.sensor.read_retry(
                            terrariumSensor.VALID_DHT_SENSORS[
                                self.get_hardware_type()],
                            float(
                                terrariumUtils.to_BCM_port_number(
                                    self.sensor_address)), 5)
                        if humidity is not None:
                            current = float(humidity)

                if current is None or not (self.get_limit_min() <= current <=
                                           self.get_limit_max()):
                    # Invalid current value.... log and ingore
                    logger.warn(
                        'Measured value %s%s from %s sensor \'%s\' is outside valid range %.2f%s - %.2f%s in %.5f seconds.'
                        % (current, self.get_indicator(), self.get_type(),
                           self.get_name(), self.get_limit_min(),
                           self.get_indicator(), self.get_limit_max(),
                           self.get_indicator(), time.time() - starttime))

                else:
                    self.current = current
                    self.last_update = now
                    logger.info(
                        'Updated %s sensor \'%s\' from %.2f%s to %.2f%s in %.5f seconds'
                        % (self.get_type(), self.get_name(), old_current,
                           self.get_indicator(), self.get_current(),
                           self.get_indicator(), time.time() - starttime))
Пример #10
0
    def _load_hardware(self):
        if terrariumUtils.parse_url(self.address):
            return self.address

        raise terrariumRelayLoadingException(f'Invalid url for relay {self}')
    def __load_forecast_data(self):
        # Onecall API's are more expensive (max 1000 a day - 1 call per 2 minutes) so we update this at a lower frequency
        address = terrariumUtils.parse_url(self.address)
        data = terrariumUtils.get_remote_data(
            'https://api.openweathermap.org/data/2.5/onecall?lat={}&lon={}&units=metric&exclude=minutely&appid={}&lang={}'
            .format(self._data['geo']['lat'], self._data['geo']['long'],
                    address['query_params']['appid'],
                    self._device['language'][0:2]))

        if data:
            self._data['days'] = []
            self._data['forecast'] = []

            for hourly in data['hourly']:
                self._data['forecast'].append({
                    'timestamp':
                    int(hourly["dt"] + self._data["timezone"]),
                    'temperature':
                    float(hourly['temp']),
                    'humidity':
                    float(hourly['humidity']),
                })

            day_periods = {
                'morn': -6 * 60 * 60,
                'day': 0,
                'eve': 6 * 60 * 60,
                'night': 12 * 60 * 60
            }
            for daily in data['daily']:

                for period in day_periods:
                    timestamp = int(daily["dt"] + self._data["timezone"] +
                                    day_periods[period])

                    # Exlude already existing and pasted hourly forecasts
                    if timestamp not in [
                            item['timestamp']
                            for item in self._data['forecast']
                    ] and timestamp > self._data['forecast'][0]['timestamp']:

                        self._data['forecast'].append({
                            'timestamp':
                            timestamp,
                            'temperature':
                            float(daily['temp'][period]),
                            'humidity':
                            float(daily['humidity']),
                        })

                    if 'day' == period:
                        # Store day data for icons
                        day = daily
                        if len(self._data['days']) == 0:
                            # First day, we use the current data
                            day = data['current']
                            day['temp'] = {period: data['current']['temp']}

                        self._data['days'].append({
                            'timestamp':
                            timestamp,
                            'rise':
                            int(day['sunrise'] + self._data["timezone"]),
                            'set':
                            int(day['sunset'] + self._data["timezone"]),
                            'temp':
                            float(day['temp'][period]),
                            'humidity':
                            float(day['humidity']),
                            'wind': {
                                'speed':
                                float(day['wind_speed']
                                      ),  # Speed is in meter per second
                                'direction': float(day['wind_deg'])
                            },
                            'weather': {
                                'description':
                                day['weather'][0].get('description', ''),
                                'icon':
                                day['weather'][0].get('icon', '')
                            }
                        })

            self._data['forecast'] = sorted(self._data['forecast'],
                                            key=lambda d: d['timestamp'])
            self._data['days'] = sorted(self._data['days'],
                                        key=lambda d: d['timestamp'])

            return True

        return False