Example #1
0
 def send_message(self, text, chat_id=None):
     if self.__running:
         chat_ids = self.__chat_ids if chat_id is None else [int(chat_id)]
         for chat_id in chat_ids:
             url = self.__bot_url + 'sendMessage?text={}&chat_id={}'.format(
                 text, chat_id)
             terrariumUtils.get_remote_data(url, proxy=self.__proxy)
Example #2
0
    def load_data(self):
        logger.info('Update {} data from ONLINE refreshing cache.'.format(
            self.get_type()))
        self.credits['text'] = 'OpenWeatherMap weather data'

        parsed_json = terrariumUtils.get_remote_data(self.source)
        if parsed_json is not None:
            # Parse general data information
            self.location['city'] = parsed_json['name']
            self.location['country'] = parsed_json['sys']['country']
            self.location['geo']['lat'] = float(parsed_json['coord']['lat'])
            self.location['geo']['long'] = float(parsed_json['coord']['lon'])

            self.credits['url'] = 'https://openweathermap.org/city/{}'.format(
                parsed_json['id'])
            self.sun['rise'] = int(parsed_json['sys']['sunrise'])
            self.sun['set'] = int(parsed_json['sys']['sunset'])

            parsed_json = terrariumUtils.get_remote_data(
                self.source.replace('/weather?q', '/forecast?q'))
            if parsed_json is not None:
                # Parse hourly and week forecast
                datelimit = int(time.time()) + (
                    2 * 24 * 60 * 60)  # Hourly forecast limit of 2 days
                for forecast in parsed_json['list']:
                    forecast_data = {
                        'from':
                        int(forecast['dt']),
                        'to':
                        int(forecast['dt']) +
                        (3 * 60 * 60),  # Data is provided per 3 hours
                        'weather':
                        forecast['weather'][0]['description'],
                        'rain': (float(forecast['rain']['3h']) /
                                 3.0) if 'rain' in forecast
                        and '3h' in forecast['rain'] else 0,  # Guess in mm
                        'humidity':
                        float(forecast['main']['humidity']),
                        'wind_direction':
                        forecast['wind']['deg'],
                        'wind_speed':
                        float(forecast['wind']['speed']),
                        'temperature':
                        float(forecast['main']['temp']),
                        'pressure':
                        float(forecast['main']['pressure'])
                    }

                    self.week_forecast[forecast_data['from']] = forecast_data
                    if forecast_data['to'] <= datelimit:
                        self.hour_forecast[
                            forecast_data['from']] = forecast_data

        else:
            logger.error('Error getting online data from {}'.format(
                self.get_type()))
            return False

        return True
Example #3
0
  def set_hardware_state(self, state, force = False):
    changed = True

    if self.__firmware is None:
      logger.error('Sonoff device is not connected. Cannot trigger power switch')
      changed = False
    else:
      data = re.match(self.VALID_SOURCE,self.get_address())
      if data:
        data = data.groupdict()
        url = None

        if 'tasmota' == self.__firmware:
          url = 'http://{}/cm?cmnd=Power%20{}'.format(data['host'],('1' if state else '0'))
          if 'user' in data and 'password' in data:
            url += '&user={}&password={}'.format(data['user'],data['password'])

        elif 'espeasy' == self.__firmware:
          url = 'http://{}/control?cmd=event,T{}'.format(data['host'],('1' if state else '0'))

        elif 'espurna' == self.__firmware:
          url = 'http://{}/api/relay/0?apikey={}&value={}'.format(data['host'],data['password'],('1' if state else '0'))

        state = terrariumUtils.get_remote_data(url)
        if state is None:
          changed = False

    return changed
Example #4
0
    def _get_hardware_value(self):
        data = terrariumUtils.get_remote_data(self.device)
        if data is None:
            return None

        data = float(data)
        return data
Example #5
0
    def load_data(self):
        self.sunrise = int(datetime.now().replace(hour=8, minute=0,
                                                  second=0).strftime('%s'))
        self.sunset = self.sunrise + (12 * 60 * 60)

        logger.info('Update Wunderground data from ONLINE refreshing cache.')
        self.type = 'weather.com'
        self.copyright = {'text': 'Wunderground weather data', 'url': ''}

        parsed_json = terrariumUtils.get_remote_data(self.source_url)
        if parsed_json is not None:
            # Parse general data information
            self.city = parsed_json['location']['city']
            self.country = parsed_json['location']['country_name']
            self.geo['lat'] = float(parsed_json['location']['lat'])
            self.geo['long'] = float(parsed_json['location']['lon'])
            self.copyright['url'] = parsed_json['location']['wuiurl']

            now = datetime.now()
            self.sunrise = time.mktime(
                now.replace(
                    hour=int(parsed_json['sun_phase']['sunrise']['hour']),
                    minute=int(parsed_json['sun_phase']['sunrise']['minute']),
                    second=0).timetuple())

            now = datetime.now(
            )  # Not sure if needed. But this will never fail!
            self.sunset = time.mktime(
                now.replace(
                    hour=int(parsed_json['sun_phase']['sunset']['hour']),
                    minute=int(parsed_json['sun_phase']['sunset']['minute']),
                    second=0).timetuple())

            # Parse hourly and week forecast
            self.hour_forecast = []
            self.week_forecast = []
            datelimit = int(time.time()) + (
                2 * 24 * 60 * 60)  # Hourly forecast limit of 2 days
            for forecast in parsed_json['hourly_forecast']:
                forecast_hour = {
                    'from': int(forecast['FCTTIME']['epoch']),
                    'to': int(forecast['FCTTIME']['epoch']) +
                    (60 * 60),  # Data is provided per 1 hour
                    'weather': forecast['condition'],
                    'rain': 0,  # Figure out the data
                    'humidity': float(forecast['humidity']),
                    'wind_direction': forecast['wdir']['dir'],
                    'wind_speed': float(forecast['wspd']['metric']) / 3.6,
                    'temperature': float(forecast['temp']['metric']),
                    'pressure': float(forecast['mslp']['metric'])
                }
                self.week_forecast.append(copy.deepcopy(forecast_hour))
                if forecast_hour['to'] <= datelimit:
                    self.hour_forecast.append(copy.deepcopy(forecast_hour))

        else:
            logger.error('Error getting online data from weather.com')
            return False

        return True
Example #6
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)
Example #7
0
    def _load_hardware(self):
        # Input format should be either:
        # - http://[HOST]#[POWER_SWITCH_NR]
        # - http://[HOST]/#[POWER_SWITCH_NR]
        # - http://[PASSWORD]@[HOST]#[POWER_SWITCH_NR]
        # - http://[PASSWORD]@[HOST]/#[POWER_SWITCH_NR]

        address = self._address

        # Try Tasmota
        # http://sonoff/cm?cmnd=Power[POWER_SWITCH_NR]%201
        # http://sonoff/cm?cmnd=Power[POWER_SWITCH_NR]%200
        # http://sonoff/cm?user=admin&password=joker&cmnd=Power[POWER_SWITCH_NR]%201

        device = f'{address["protocol"]}://{address["host"]}/cm?'

        if 'user' in address and 'password' in address:
            device += f'user={address["user"]}&password={address["password"]}&'

        device += 'cmnd='
        state = terrariumUtils.get_remote_data(f'{device}Status%200')

        if state is None:
            return None

        # Always overule the ID generating, as we want to use the MAC as that is unique if the IP address is changing
        self.id = md5(f'{self.HARDWARE}{state["StatusNET"]["Mac"].lower()}'.
                      encode()).hexdigest()

        return device
Example #8
0
    def load_data(self):
        logger.info('Update {} data from ONLINE refreshing cache.'.format(
            self.get_type()))
        self.credits['text'] = 'Wunderground weather data'

        parsed_json = terrariumUtils.get_remote_data(self.source)
        if parsed_json is not None:
            # Parse general data information
            self.location['city'] = parsed_json['location']['city']
            self.location['country'] = parsed_json['location']['country_name']
            self.location['geo']['lat'] = float(parsed_json['location']['lat'])
            self.location['geo']['long'] = float(
                parsed_json['location']['lon'])

            self.credits['url'] = parsed_json['location']['wuiurl']

            now = datetime.now()
            self.sun['rise'] = int(
                time.mktime(
                    now.replace(
                        hour=int(parsed_json['sun_phase']['sunrise']['hour']),
                        minute=int(
                            parsed_json['sun_phase']['sunrise']['minute']),
                        second=0).timetuple()))
            now = datetime.now()
            self.sun['set'] = int(
                time.mktime(
                    now.replace(
                        hour=int(parsed_json['sun_phase']['sunset']['hour']),
                        minute=int(
                            parsed_json['sun_phase']['sunset']['minute']),
                        second=0).timetuple()))

            # Parse hourly and week forecast
            datelimit = int(time.time()) + (
                2 * 24 * 60 * 60)  # Hourly forecast limit of 2 days
            for forecast in parsed_json['hourly_forecast']:
                forecast_data = {
                    'from': int(forecast['FCTTIME']['epoch']),
                    'to': int(forecast['FCTTIME']['epoch']) +
                    (60 * 60),  # Data is provided per 1 hour
                    'weather': forecast['condition'],
                    'rain': 0.0,  # Figure out the data
                    'humidity': float(forecast['humidity']),
                    'wind_direction': forecast['wdir']['dir'],
                    'wind_speed': float(forecast['wspd']['metric']) / 3.6,
                    'temperature': float(forecast['temp']['metric']),
                    'pressure': float(forecast['mslp']['metric'])
                }

                self.week_forecast[forecast_data['from']] = forecast_data
                if forecast_data['to'] <= datelimit:
                    self.hour_forecast[forecast_data['from']] = forecast_data

        else:
            logger.error('Error getting online data from {}'.format(
                self.get_type()))
            return False

        return True
  def set_hardware_state(self, state, force = False):
    changed = True

    if self.__firmware is None:
      if self.__retries < 5:
        self.__retries += 1
        logger.warning('Sonoff device is not connected for trigger action. Reconnect attempt: {}'.format(self.__retries))
        self.load_hardware()
        return self.set_hardware_state(state,force)
      else:
        logger.error('Sonoff device is not connected. Cannot trigger power switch')
        return False

    data = re.match(self.VALID_SOURCE,self.get_address())
    if data:
      data = data.groupdict()
      url = None

      if 'tasmota' == self.__firmware:
        url = self.url + '%20{}'.format('1' if state else '0')

      elif 'espeasy' == self.__firmware:
        url = 'http://{}/control?cmd=event,T{}'.format(data['host'],('1' if state else '0'))

      elif 'espurna' == self.__firmware:
        url = 'http://{}/api/relay/0?apikey={}&value={}'.format(data['host'],data['password'],('1' if state else '0'))

      state = terrariumUtils.get_remote_data(url)
      if state is None:
        changed = False

    return changed
Example #10
0
    def _get_hardware_value(self):
        url = f'{self.device}Dimmer'
        data = terrariumUtils.get_remote_data(url)

        if data is not None and 'Dimmer' in data:
            return int(data['Dimmer'])

        return None
Example #11
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
Example #12
0
    def _set_hardware_value(self, state):
        state = int(max(0.0, min(100.0, float(state + self._dimmer_offset))))

        url = f'{self.device}Dimmer%20{state}'
        data = terrariumUtils.get_remote_data(url)

        if data is None:
            return False

        return state == int(data['Dimmer'])
  def __get_updates(self,offset=None):
    self.__last_update_check = int(time.time())
    url = self.__bot_url + 'getUpdates?timeout={}'.format(terrariumNotificationTelegramBot.__POLL_TIMEOUT)
    if offset:
      url += '&offset={}'.format(offset)

    data = terrariumUtils.get_remote_data(url,terrariumNotificationTelegramBot.__POLL_TIMEOUT + 3,proxy=self.__proxy)
    if data is None:
      data = {'description' : 'Did not receive valid JSON data'}

    return data
Example #14
0
  def get_raw_data(self):
    logger.debug('Using URL: %s' % (self.location,))
    try:
      remote_image = terrariumUtils.get_remote_data(self.location)
      if remote_image is None:
        raise terrariumWebcamRAWUpdateException()

      self.raw_image = BytesIO(remote_image)
      return True
    except terrariumWebcamRAWUpdateException as ex:
      logger.warning('Error getting raw online image from webcam \'%s\' with error message: %s' % (self.get_name(),ex))

    return False
Example #15
0
    def _set_hardware_value(self, state):
        action = 1 if state == self.ON else 0
        url = f'{self.device}Power{self._address["nr"]}%20{action}'
        data = terrariumUtils.get_remote_data(url)

        if data is None:
            return False

        if 'POWER' in data:
            data = data['POWER']
        elif f'POWER{self._address["nr"]}' in data:
            data = data[f'POWER{self._address["nr"]}']

        return state == (self.ON if terrariumUtils.is_true(data) else self.OFF)
Example #16
0
    def get_hardware_state(self):
        data = None

        if self.__firmware is None:
            logger.error(
                'Sonoff device is not connected. Cannot read power switch state'
            )
            return terrariumPowerSwitch.OFF
        else:
            data = re.match(self.VALID_SOURCE, self.get_address())
            if data:
                data = data.groupdict()
                url = None

                if 'tasmota' == self.__firmware:
                    url = 'http://{}/cm?cmnd=Power'.format(data['host'])
                    if 'user' in data and 'password' in data:
                        url += '&user={}&password={}'.format(
                            data['user'], data['password'])

                elif 'espeasy' == self.__firmware:
                    url = 'http://{}/json'.format(data['host'])

                elif 'espurna' == self.__firmware:
                    if 'password' not in data:
                        # Just add dummy value...
                        data['password'] = '******'

                    url = 'http://{}/apis?apikey={}'.format(
                        data['host'], data['password'])

                state = terrariumUtils.get_remote_data(url)
                if state is None:
                    logger.warning(
                        'Error reading Sonoff \'{}\' power state. So retruning last known state: {}'
                        .format(self.get_name(), self.state))
                    return self.state

                if 'tasmota' == self.__firmware:
                    return terrariumPowerSwitch.ON if terrariumUtils.is_true(
                        state['POWER']) else terrariumPowerSwitch.OFF
                elif 'espeasy' == self.__firmware:
                    return terrariumPowerSwitch.ON if terrariumUtils.is_true(
                        state['POWER']) else terrariumPowerSwitch.OFF
                elif 'espurna' == self.__firmware:
                    return terrariumPowerSwitch.ON if terrariumUtils.is_true(
                        state['POWER']) else terrariumPowerSwitch.OFF

        return 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
  def get_hardware_state(self):
    data = None

    if self.__firmware is None:
      if self.__retries < 5:
        self.__retries += 1
        logger.warning('Sonoff device is not connected while reading the state. Reconnect attempt: {}'.format(self.__retries))
        self.load_hardware()
        return self.get_hardware_state()
      else:
        logger.error('Sonoff device is not connected. Cannot read power switch state')
        return terrariumPowerSwitch.OFF

    data = re.match(self.VALID_SOURCE,self.get_address())
    if data:
      data = data.groupdict()
      url = None

      if 'tasmota' == self.__firmware:
        url = self.url

      elif 'espeasy' == self.__firmware:
        url = 'http://{}/json'.format(data['host'])

      elif 'espurna' == self.__firmware:
        if 'password' not in data:
          # Just add dummy value...
          data['password'] = '******'

        url = 'http://{}/apis?apikey={}'.format(data['host'],data['password'])

      state = terrariumUtils.get_remote_data(url)
      if state is None:
        logger.warning('Error reading Sonoff \'{}\' power state. So returning last known state: {}'.format(self.get_name(),self.state))
        return self.state

      if 'tasmota' == self.__firmware:
        for state_name, state_value in state.items():
          if state_name.startswith('POWER'):
            return terrariumPowerSwitch.ON if terrariumUtils.is_true(state_value) else terrariumPowerSwitch.OFF
      elif 'espeasy' == self.__firmware:
        return terrariumPowerSwitch.ON if terrariumUtils.is_true(state['POWER']) else terrariumPowerSwitch.OFF
      elif 'espurna' == self.__firmware:
        return terrariumPowerSwitch.ON if terrariumUtils.is_true(state['POWER']) else terrariumPowerSwitch.OFF

    return terrariumPowerSwitch.OFF
Example #19
0
    def _get_hardware_value(self):
        data = self.__cache.get_data(self.__cache_key)
        if data is None:
            # Cache is expired, so we update with new data
            # Get the overall state information
            url = f'{self.device}State'
            data = terrariumUtils.get_remote_data(url)

            if data is None:
                return None

            self.__cache.set_data(self.__cache_key, data, self._CACHE_TIMEOUT)

        if 'POWER' in data:
            data = data['POWER']
        elif f'POWER{self._address["nr"]}' in data:
            data = data[f'POWER{self._address["nr"]}']

        return self.ON if terrariumUtils.is_true(data) else self.OFF
Example #20
0
    def _load_hardware(self):
        # Input format should be either:
        # - http://[HOST]#[POWER_SWITCH_NR]
        # - http://[HOST]/#[POWER_SWITCH_NR]
        # - http://[PASSWORD]@[HOST]#[POWER_SWITCH_NR]
        # - http://[PASSWORD]@[HOST]/#[POWER_SWITCH_NR]

        address = self._address

        # Try Tasmota
        # http://sonoff/cm?cmnd=Power[POWER_SWITCH_NR]%201
        # http://sonoff/cm?cmnd=Power[POWER_SWITCH_NR]%200
        # http://sonoff/cm?user=admin&password=joker&cmnd=Power[POWER_SWITCH_NR]%201

        device = f'{address["protocol"]}://{address["host"]}/cm?'

        if 'user' in address and 'password' in address:
            device += f'user={address["user"]}&password={address["password"]}&'

        device += 'cmnd='
        state = terrariumUtils.get_remote_data(f'{device}Status%200')

        if state is None:
            return None

        # Create the cache key for caching the relay states.
        # This is usefull when there are more then 1 relay per hardware device.
        self.__cache_key = md5(
            f'{self.HARDWARE}{state["StatusNET"]["Mac"].lower()}'.encode(
            )).hexdigest()
        self.__cache = terrariumCache()
        self.__cache.set_data(self.__cache_key, state['StatusSTS'],
                              self._CACHE_TIMEOUT)

        # We need the use the address_nr value also, as there can multiple relays per sonoff device.
        if self._device['id'] is None:
            self.id = md5(
                f'{self.HARDWARE}{state["StatusNET"]["Mac"].lower()}{address["nr"]}'
                .encode()).hexdigest()

        return device
Example #21
0
  def _get_data(self):
    value = self._sensor_cache.get_data(self.__source_cache_key)

    if value is None:
      value = terrariumUtils.get_remote_data(self.device)
      if value is None:
        return None

      self._sensor_cache.set_data(self.__source_cache_key,value, self._CACHE_TIMEOUT)

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

      value = value[item]

    data = { self.sensor_type : value }
    return data
    def __load_general_data(self):
        address = self.address + '&units=metric&lang=' + self._device[
            'language'][0:2]
        logger.debug('Loading weather source {}'.format(address))
        data = terrariumUtils.get_remote_data(self.address)
        if data:
            self._data['city'] = data['name']
            self._data['country'] = data['sys']['country']
            self._data['geo'] = {
                'lat': float(data['coord']['lat']),
                'long': float(data['coord']['lon'])
            }
            self._data['url'] = 'https://openweathermap.org/city/{}'.format(
                data['id'])
            self._data['credits'] = 'OpenWeatherMap weather data'
            self._data['timezone'] = int(data['timezone'])

            return True

        logger.warning(
            'Error loading online weather data from source {} !'.format(
                address))
        return False
Example #23
0
  def load_hardware(self):
    self.__firmware = None
    # Input format should be either:
    # - http://[HOST]#[POWER_SWITCH_NR]
    # - http://[HOST]/#[POWER_SWITCH_NR]
    # - http://[PASSWORD]@[HOST]#[POWER_SWITCH_NR]
    # - http://[PASSWORD]@[HOST]/#[POWER_SWITCH_NR]

    data = re.match(self.VALID_SOURCE,self.get_address())
    if data:
      data = data.groupdict()

      try:
        # Try Tasmota

        # http://sonoff/cm?cmnd=Power%20TOGGLE
        # http://sonoff/cm?cmnd=Power%20On
        # http://sonoff/cm?cmnd=Power%20off
        # http://sonoff/cm?user=admin&password=joker&cmnd=Power%20Toggle

        url = 'http://{}/cm?cmnd=Power'.format(data['host'])
        if 'user' in data and 'password' in data:
          url += '&user={}&password={}'.format(data['user'],data['password'])

        state = terrariumUtils.get_remote_data(url)
        if state is None:
          raise Exception('No data, jump to next test')

        self.__firmware = 'tasmota'

      except Exception as ex:
        print('Tasmota exceptions')
        print(ex)


      if self.__firmware is None:
        try:
          # Try ESP Easy

          # url_switch_on  = 'http://192.168.1.42/control?cmd=event,T1'
          # url_switch_off  = 'http://192.168.1.42/control?cmd=event,T0'

          #print('Test ESP Easy')

          url = 'http://{}/json'.format(data['host'])
          # No information about using username and password:
          # https://www.letscontrolit.com/wiki/index.php?title=ESPEasy_Command_Reference
          # https://www.letscontrolit.com/wiki/index.php?title=ESP_Easy_web_interface#JSON_page_.28hidden_prior_to_version_2.0.2B.29

          #print(url)
          state = terrariumUtils.get_remote_data(url)
          #print('Result')
          #print(state)
          if state is None:
            raise Exception('No data, jump to next test')

          self.__firmware = 'espeasy'

        except Exception as ex:
          print('ESP Easy exceptions')
          print(ex)

      if self.__firmware is None:
        try:
          # Try ESPurna
          # https://github.com/xoseperez/espurna/wiki/RESTAPI

          # http://192.168.1.108/apis?apikey=C62ED7BE7593B658
          # http://192.168.1.108/api/relay/0?apikey=C62ED7BE7593B658&value=0 (off)
          # http://192.168.1.108/api/relay/0?apikey=C62ED7BE7593B658&value=1 (on)
          # http://192.168.1.108/api/relay/0?apikey=C62ED7BE7593B658&value=2 (toggle)


          #print('Test ESPurna')

          if 'password' not in data:
            # Just add dummy value...
            data['password'] = '******'

          url = 'http://{}/apis?apikey={}'.format(data['host'],data['password'])

          #print(url)
          state = terrariumUtils.get_remote_data(url,json=True)
          #print('Result')
          #print(state)
          if state is None:
            raise Exception('No data, this was the last attempt...')

          self.__firmware = 'espurna'

        except Exception as ex:
          print('ESPurna exceptions')
          print(ex)
Example #24
0
    def load_data(self):
        data = terrariumUtils.get_remote_data(self.get_address())
        if data is None:
            return None

        return {self.get_sensor_type(): data}
Example #25
0
 def __get_raw_data(self):
     if self.__url is not None:
         self.__value = terrariumUtils.get_remote_data(self.__url)
Example #26
0
    def load_data(self):
        self.sunrise = int(datetime.now().replace(hour=8, minute=0,
                                                  second=0).strftime('%s'))
        self.sunset = self.sunrise + (12 * 60 * 60)

        starttime = time.time()
        logger.info('Update YR.no data from ONLINE refreshing cache.')
        self.type = 'yr.no'

        xmldata = terrariumUtils.get_remote_data(
            self.source_url.strip('/') + '/forecast_hour_by_hour.xml')
        if xmldata is not None:
            try:
                xmldata = untangle.parse(xmldata)
            except Exception:
                logger.exception('Error getting online data from yr.no')
                return False

            # Parse hour forecast
            # Parse general data information
            self.city = xmldata.weatherdata.location.name.cdata
            self.country = xmldata.weatherdata.location.country.cdata
            self.geo['lat'] = float(
                xmldata.weatherdata.location.location['latitude'])
            self.geo['long'] = float(
                xmldata.weatherdata.location.location['longitude'])
            self.copyright['text'] = xmldata.weatherdata.credit.link['text']
            self.copyright['url'] = xmldata.weatherdata.credit.link['url']
            self.sunrise = time.mktime(
                dateutil.parser.parse(
                    xmldata.weatherdata.sun['rise']).timetuple())
            self.sunset = time.mktime(
                dateutil.parser.parse(
                    xmldata.weatherdata.sun['set']).timetuple())

            self.hour_forecast = []
            for forecast in xmldata.weatherdata.forecast.tabular.time:
                self.hour_forecast.append({
                    'from':
                    time.mktime(
                        dateutil.parser.parse(forecast['from']).timetuple()),
                    'to':
                    time.mktime(
                        dateutil.parser.parse(forecast['to']).timetuple()),
                    'weather':
                    forecast.symbol['name'],
                    'rain':
                    float(forecast.precipitation['value']),
                    'humidity':
                    0,
                    'wind_direction':
                    forecast.windDirection['name'],
                    'wind_speed':
                    float(forecast.windSpeed['mps']),
                    'temperature':
                    float(forecast.temperature['value']),
                    'pressure':
                    float(forecast.pressure['value'])
                })

            # Parse week forecast
            self.week_forecast = []
            xmldata = terrariumUtils.get_remote_data(
                self.source_url.strip('/') + '/forecast.xml')
            if xmldata is not None:
                try:
                    xmldata = untangle.parse(xmldata)
                except Exception:
                    logger.exception('Error getting online data from yr.no')

                #xmldata = untangle.parse(self.source_url.strip('/') + '/forecast.xml')
                for forecast in xmldata.weatherdata.forecast.tabular.time:
                    self.week_forecast.append({
                        'from':
                        time.mktime(
                            dateutil.parser.parse(
                                forecast['from']).timetuple()),
                        'to':
                        time.mktime(
                            dateutil.parser.parse(forecast['to']).timetuple()),
                        'weather':
                        forecast.symbol['name'],
                        'rain':
                        float(forecast.precipitation['value']),
                        'humidity':
                        0,
                        'wind_direction':
                        forecast.windDirection['name'],
                        'wind_speed':
                        float(forecast.windSpeed['mps']),
                        'temperature':
                        float(forecast.temperature['value']),
                        'pressure':
                        float(forecast.pressure['value'])
                    })
            else:
                logger.error('Error getting online data from yr.no')
        else:
            logger.error('Error getting online data from yr.no')
            return False

        return True
Example #27
0
    def load_data(self):
        self.sunrise = int(datetime.now().replace(hour=8, minute=0,
                                                  second=0).strftime('%s'))
        self.sunset = self.sunrise + (12 * 60 * 60)

        logger.info('Update OpenWeatherMap data from ONLINE refreshing cache.')
        self.type = 'openweathermap.org'
        self.copyright = {
            'text': 'OpenWeatherMap data',
            'url': 'https://openweathermap.org/city/'
        }

        parsed_json = terrariumUtils.get_remote_data(self.source_url)
        if parsed_json is not None:
            # Parse general data information
            self.city = parsed_json['name']
            self.country = parsed_json['sys']['country']
            self.geo['lat'] = float(parsed_json['coord']['lat'])
            self.geo['long'] = float(parsed_json['coord']['lon'])
            self.copyright['url'] = 'https://openweathermap.org/city/' + str(
                parsed_json['id'])
            self.sunrise = parsed_json['sys']['sunrise']
            self.sunset = parsed_json['sys']['sunset']

            self.hour_forecast = []
            self.week_forecast = []

            parsed_json = terrariumUtils.get_remote_data(
                self.source_url.replace('/weather?q', '/forecast?q'))
            if parsed_json is not None:
                # Parse hourly and week forecast
                datelimit = int(time.time()) + (
                    2 * 24 * 60 * 60)  # Hourly forecast limit of 2 days
                for forecast in parsed_json['list']:
                    forecast_hour = {
                        'from':
                        forecast['dt'],
                        'to':
                        forecast['dt'] +
                        (3 * 60 * 60),  # Data is provided per 3 hours
                        'weather':
                        forecast['weather'][0]['description'],
                        'rain': (float(forecast['rain']['3h']) /
                                 3.0) if 'rain' in forecast
                        and '3h' in forecast['rain'] else 0,  # Guess in mm
                        'humidity':
                        float(forecast['main']['humidity']),
                        'wind_direction':
                        forecast['wind']['deg'],
                        'wind_speed':
                        float(forecast['wind']['speed']) / 3.6,
                        'temperature':
                        float(forecast['main']['temp']),
                        'pressure':
                        float(forecast['main']['pressure'])
                    }
                    self.week_forecast.append(copy.deepcopy(forecast_hour))
                    if forecast_hour['to'] <= datelimit:
                        self.hour_forecast.append(copy.deepcopy(forecast_hour))

        else:
            logger.error('Error getting online data from openweathermap.org')
            return False

        return True
Example #28
0
    def _load_hardware(self):
        data = terrariumUtils.get_remote_data(self.address)
        if data is not None:
            return self.address

        return None
Example #29
0
    def load_data(self):
        starttime = time.time()
        logger.info('Update {} data from ONLINE refreshing cache.'.format(
            self.get_type()))

        xmldata = terrariumUtils.get_remote_data(
            self.source.strip('/') + '/forecast_hour_by_hour.xml')
        if xmldata is not None:
            try:
                xmldata = untangle.parse(xmldata)
            except Exception:
                logger.exception('Error getting online data from {}'.format(
                    self.get_type()))
                return False

            # Parse hour forecast
            # Parse general data information
            self.location['city'] = xmldata.weatherdata.location.name.cdata
            self.location[
                'country'] = xmldata.weatherdata.location.country.cdata
            self.location['geo']['lat'] = float(
                xmldata.weatherdata.location.location['latitude'])
            self.location['geo']['long'] = float(
                xmldata.weatherdata.location.location['longitude'])

            self.credits['text'] = xmldata.weatherdata.credit.link['text']
            self.credits['url'] = xmldata.weatherdata.credit.link['url']

            self.sun['rise'] = int(
                time.mktime(
                    dateutil.parser.parse(
                        xmldata.weatherdata.sun['rise']).timetuple()))
            self.sun['set'] = int(
                time.mktime(
                    dateutil.parser.parse(
                        xmldata.weatherdata.sun['set']).timetuple()))

            for forecast in xmldata.weatherdata.forecast.tabular.time:
                forecast_data = {
                    'from':
                    int(
                        time.mktime(
                            dateutil.parser.parse(
                                forecast['from']).timetuple())),
                    'to':
                    int(
                        time.mktime(
                            dateutil.parser.parse(
                                forecast['to']).timetuple())),
                    'weather':
                    forecast.symbol['name'],
                    'rain':
                    float(forecast.precipitation['value']),
                    'humidity':
                    0.0,
                    'wind_direction':
                    forecast.windDirection['name'],
                    'wind_speed':
                    float(forecast.windSpeed['mps']),
                    'temperature':
                    float(forecast.temperature['value']),
                    'pressure':
                    float(forecast.pressure['value'])
                }

                self.hour_forecast[forecast_data['from']] = forecast_data

            # Parse week forecast
            xmldata = terrariumUtils.get_remote_data(
                self.source.strip('/') + '/forecast.xml')
            if xmldata is not None:
                try:
                    xmldata = untangle.parse(xmldata)
                except Exception:
                    logger.exception(
                        'Error getting online data from {}'.format(
                            self.get_type()))

                for forecast in xmldata.weatherdata.forecast.tabular.time:
                    forecast_data = {
                        'from':
                        int(
                            time.mktime(
                                dateutil.parser.parse(
                                    forecast['from']).timetuple())),
                        'to':
                        int(
                            time.mktime(
                                dateutil.parser.parse(
                                    forecast['to']).timetuple())),
                        'weather':
                        forecast.symbol['name'],
                        'rain':
                        float(forecast.precipitation['value']),
                        'humidity':
                        0.0,
                        'wind_direction':
                        forecast.windDirection['name'],
                        'wind_speed':
                        float(forecast.windSpeed['mps']),
                        'temperature':
                        float(forecast.temperature['value']),
                        'pressure':
                        float(forecast.pressure['value'])
                    }
                    self.week_forecast[forecast_data['from']] = forecast_data

            else:
                logger.error('Error getting online data from {}'.format(
                    self.get_type()))
        else:
            logger.error('Error getting online data from {}'.format(
                self.get_type()))
            return False

        return True
Example #30
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()))