Example #1
0
 def get_sensors(self):
   logging.debug("getting temperature and other sensor data")
   try:
     val = requests.get("https://dweet.io/get/latest/dweet/for/%s-sensors" % self._thingid,
                        timeout=self._requests_timeout).json()
     delta = (TimeStamp()-TimeStamp.from_iso_str(val["with"][0]["created"])).total_seconds()*1000
     if delta > self._temp_tolerance_ms:
       raise Exception("temperature data is too old (> %d ms)" % self._temp_tolerance_ms)
     self.temp = float(val["with"][0]["content"]["temp"]);
     self._humi = float(val["with"][0]["content"].get("humi", None));
     self._sensors_errors = 0
   except Exception as e:
     self._sensors_errors = self._sensors_errors + 1
     if self._sensors_errors >= self._sensors_errors_tolerance:
       logging.error("too many sensors reading errors (%d out of %d): resetting data: %s" %
                     (self._sensors_errors, self._sensors_errors_tolerance, e))
       self.temp = None
       self._humi = None
     else:
       logging.warning("sensor error, retaining old data: %s" % e)
   logging.debug("sensor data: temp=%s, humidity=%s" %
                 (self.temp  and "%.1f°C" % self.temp  or "n/a",
                  self._humi and "%.1f%%" % self._humi or "n/a"))
Example #2
0
  def get_latest_command(self):

    logging.debug('checking for commands')
    skipped = 0

    try:
      r = requests.get("https://dweet.io/get/dweets/for/%s" % self._thingid,
                       timeout=self._requests_timeout)
    except requests.exceptions.RequestException as e:
      logging.error('failed to get latest commands: %s' % e)
      return False

    if r.status_code != 200:
      logging.error('invalid status code received: %d' % r.status_code)
      return False

    try:

      for idx,item in enumerate( r.json()['with'] ):

        try:

          now_ts = TimeStamp()
          msg_ts = TimeStamp.from_iso_str( item['created'] )

          if (now_ts-msg_ts).total_seconds() <= self._cmd_expiry_s:
            # consider this message: it is still valid

            # nonce must be unique
            nonce = item['content']['nonce']
            nonce_is_unique = True

            for ridx, ritem in reversed( list(enumerate(r.json()['with']))[idx+1:] ):
              if 'nonce' in ritem['content'] and nonce == ritem['content']['nonce']:
                nonce_is_unique = False
                break

            if nonce_is_unique:
              msg = self.decrypt_msg(item['content'])

            if not nonce_is_unique:
              logging.warning('duplicated nonce (%s): possible replay attack, ignoring' % nonce)

            elif msg is None:
              logging.warning('cannot decrypt message, check password')

            else:

              msg_real_ts = TimeStamp.from_iso_str( msg['timestamp'] )
              msg_delta = msg_ts - msg_real_ts

              if abs(msg_delta.total_seconds())*1000 > self._tolerance_ms:
                logging.warning('message timestamps mismatch, ignoring')

              elif msg['type'].lower() == 'command':

                logging.debug('found valid command')
                logging.debug(json.dumps(msg, indent=2))

                save = False
                if msg['override_program'] != self._override_program:
                  save = True
                if msg['program'] != self._program:
                  save = True
                lid = msg['id']

                self._override_program = msg['override_program']
                self._program = msg['program']
                self._lastcmd_id = lid

                if save:
                  if self.save_conf():
                    logging.info('new configuration saved')
                  else:
                    logging.error('cannot save new configuration')

                break

          else:
            # messages from now on are too old, no need to parse the rest
            logging.debug('found first outdated message, skipping the rest')
            break

        except (KeyError, TypeError) as e:
          logging.debug('error parsing, skipped: %s' % e)
          skipped = skipped+1
          pass

    except Exception as e:
      logging.error('error parsing response: %s' % e)
      return False

    if skipped > 0:
      logging.warning('invalid messages skipped: %d' % skipped)
    return True